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 caps = gst_caps_ref(ref_caps);
1727 caps_str = gst_caps_to_string(caps);
1729 LOGD("detected mimetype : %s", name);
1731 if (strstr(name, "audio")) {
1732 if (player->pipeline->audiobin == NULL) {
1733 const gchar *audio_format = gst_structure_get_string(str, "format");
1735 LOGD("original audio format %s", audio_format);
1736 mm_player_set_attribute((MMHandleType)player, NULL,
1737 "content_audio_format", audio_format, strlen(audio_format), NULL);
1740 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1741 LOGE("failed to create audiobin. continuing without audio");
1745 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1746 LOGD("creating audiobin success");
1749 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1750 LOGD("reusing audiobin");
1751 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1753 } else if (strstr(name, "video")) {
1754 /* 1. zero copy is updated at _decode_pad_added()
1755 * 2. NULL surface type is handled in _decode_pad_added() */
1756 LOGD("zero copy %d", player->set_mode.video_zc);
1757 if (player->pipeline->videobin == NULL) {
1758 int surface_type = 0;
1759 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1760 LOGD("display_surface_type (%d)", surface_type);
1762 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1763 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1764 LOGE("failed to acquire video overlay resource");
1768 player->interrupted_by_resource = FALSE;
1770 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1771 LOGE("failed to create videobin. continuing without video");
1775 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1776 LOGD("creating videosink bin success");
1779 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1780 LOGD("re-using videobin");
1781 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1783 } else if (strstr(name, "text")) {
1784 if (player->pipeline->textbin == NULL) {
1785 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1786 LOGE("failed to create text sink bin. continuing without text");
1790 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1791 player->textsink_linked = 1;
1792 LOGD("creating textsink bin success");
1794 if (!player->textsink_linked) {
1795 LOGD("re-using textbin");
1797 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1798 player->textsink_linked = 1;
1800 /* linked textbin exist which means that the external subtitle path exist already */
1801 LOGW("ignoring internal subtitle since external subtitle is available");
1804 sink_pad_name = "text_sink";
1806 LOGW("unknown mime type %s, ignoring it", name);
1810 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1813 LOGD("[handle: %p] success to create and link sink bin", player);
1815 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1816 * streaming task. if the task blocked, then buffer will not flow to the next element
1817 *(autoplugging element). so this is special hack for streaming. please try to remove it
1819 /* dec stream count. we can remove fakesink if it's zero */
1820 if (player->num_dynamic_pad)
1821 player->num_dynamic_pad--;
1823 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1825 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1826 _mmplayer_pipeline_complete(NULL, player);
1830 MMPLAYER_FREEIF(caps_str);
1833 gst_caps_unref(caps);
1839 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1841 int required_angle = 0; /* Angle required for straight view */
1842 int rotation_angle = 0;
1844 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1845 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1847 /* Counter clockwise */
1848 switch (orientation) {
1853 required_angle = 270;
1856 required_angle = 180;
1859 required_angle = 90;
1863 rotation_angle = display_angle + required_angle;
1864 if (rotation_angle >= 360)
1865 rotation_angle -= 360;
1867 /* check if supported or not */
1868 if (rotation_angle % 90) {
1869 LOGD("not supported rotation angle = %d", rotation_angle);
1873 switch (rotation_angle) {
1875 *value = MM_DISPLAY_ROTATION_NONE;
1878 *value = MM_DISPLAY_ROTATION_90;
1881 *value = MM_DISPLAY_ROTATION_180;
1884 *value = MM_DISPLAY_ROTATION_270;
1888 LOGD("setting rotation property value : %d", *value);
1894 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1896 int display_rotation = 0;
1897 gchar *org_orient = NULL;
1898 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1901 LOGE("cannot get content attribute");
1902 return MM_ERROR_PLAYER_INTERNAL;
1905 if (display_angle) {
1906 /* update user rotation */
1907 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1909 /* Counter clockwise */
1910 switch (display_rotation) {
1911 case MM_DISPLAY_ROTATION_NONE:
1914 case MM_DISPLAY_ROTATION_90:
1915 *display_angle = 90;
1917 case MM_DISPLAY_ROTATION_180:
1918 *display_angle = 180;
1920 case MM_DISPLAY_ROTATION_270:
1921 *display_angle = 270;
1924 LOGW("wrong angle type : %d", display_rotation);
1927 LOGD("check user angle: %d", *display_angle);
1931 /* Counter clockwise */
1932 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1935 if (!strcmp(org_orient, "rotate-90"))
1937 else if (!strcmp(org_orient, "rotate-180"))
1939 else if (!strcmp(org_orient, "rotate-270"))
1942 LOGD("original rotation is %s", org_orient);
1944 LOGD("content_video_orientation get fail");
1947 LOGD("check orientation: %d", *orientation);
1950 return MM_ERROR_NONE;
1953 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1955 int rotation_value = 0;
1956 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1957 int display_angle = 0;
1960 /* check video sinkbin is created */
1961 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1964 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1966 /* get rotation value to set */
1967 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1968 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1969 LOGD("set video param : rotate %d", rotation_value);
1972 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1974 MMHandleType attrs = 0;
1978 /* check video sinkbin is created */
1979 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1982 attrs = MMPLAYER_GET_ATTRS(player);
1983 MMPLAYER_RETURN_IF_FAIL(attrs);
1985 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1986 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1987 LOGD("set video param : visible %d", visible);
1990 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1992 MMHandleType attrs = 0;
1993 int display_method = 0;
1996 /* check video sinkbin is created */
1997 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2000 attrs = MMPLAYER_GET_ATTRS(player);
2001 MMPLAYER_RETURN_IF_FAIL(attrs);
2003 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2004 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2005 LOGD("set video param : method %d", display_method);
2008 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2010 MMHandleType attrs = 0;
2014 /* check video sinkbin is created */
2015 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2018 attrs = MMPLAYER_GET_ATTRS(player);
2019 MMPLAYER_RETURN_IF_FAIL(attrs);
2021 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2022 MMPLAYER_RETURN_IF_FAIL(handle);
2024 gst_video_overlay_set_video_roi_area(
2025 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2026 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2027 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2028 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2031 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2033 MMHandleType attrs = 0;
2038 int win_roi_width = 0;
2039 int win_roi_height = 0;
2042 /* check video sinkbin is created */
2043 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2046 attrs = MMPLAYER_GET_ATTRS(player);
2047 MMPLAYER_RETURN_IF_FAIL(attrs);
2049 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2050 MMPLAYER_RETURN_IF_FAIL(handle);
2052 /* It should be set after setting window */
2053 mm_attrs_multiple_get(attrs, NULL,
2054 "display_win_roi_x", &win_roi_x,
2055 "display_win_roi_y", &win_roi_y,
2056 "display_win_roi_width", &win_roi_width,
2057 "display_win_roi_height", &win_roi_height, NULL);
2059 /* After setting window handle, set display roi area */
2060 gst_video_overlay_set_display_roi_area(
2061 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2062 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2063 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2064 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2067 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2069 MMHandleType attrs = 0;
2072 /* check video sinkbin is created */
2073 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2076 attrs = MMPLAYER_GET_ATTRS(player);
2077 MMPLAYER_RETURN_IF_FAIL(attrs);
2079 /* common case if using overlay surface */
2080 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2081 MMPLAYER_RETURN_IF_FAIL(handle);
2083 /* default is using wl_surface_id */
2084 LOGD("set video param : wl_surface_id %d", handle);
2085 gst_video_overlay_set_wl_window_wl_surface_id(
2086 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2091 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2093 gboolean update_all_param = FALSE;
2097 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2098 LOGW("videosink is not ready yet");
2099 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2102 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2103 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2104 return MM_ERROR_PLAYER_INTERNAL;
2107 LOGD("param_name : %s", param_name);
2108 if (!g_strcmp0(param_name, "update_all_param"))
2109 update_all_param = TRUE;
2111 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2112 __mmplayer_video_param_set_display_overlay(player);
2113 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2114 __mmplayer_video_param_set_display_method(player);
2115 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2116 __mmplayer_video_param_set_display_visible(player);
2117 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2118 __mmplayer_video_param_set_display_rotation(player);
2119 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2120 __mmplayer_video_param_set_roi_area(player);
2121 if (update_all_param)
2122 __mmplayer_video_param_set_video_roi_area(player);
2126 return MM_ERROR_NONE;
2130 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2132 gboolean disable_overlay = FALSE;
2133 mmplayer_t *player = (mmplayer_t *)hplayer;
2136 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2137 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2138 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2139 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2141 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2142 LOGW("Display control is not supported");
2143 return MM_ERROR_PLAYER_INTERNAL;
2146 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2148 if (audio_only == (bool)disable_overlay) {
2149 LOGE("It's the same with current setting: (%d)", audio_only);
2150 return MM_ERROR_NONE;
2154 LOGE("disable overlay");
2155 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2157 /* release overlay resource */
2158 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2159 LOGE("failed to release overlay resource");
2163 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2164 LOGE("failed to acquire video overlay resource");
2167 player->interrupted_by_resource = FALSE;
2169 LOGD("enable overlay");
2170 __mmplayer_video_param_set_display_overlay(player);
2171 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2176 return MM_ERROR_NONE;
2180 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2182 mmplayer_t *player = (mmplayer_t *)hplayer;
2183 gboolean disable_overlay = FALSE;
2187 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2188 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2189 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2190 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2191 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2193 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2194 LOGW("Display control is not supported");
2195 return MM_ERROR_PLAYER_INTERNAL;
2198 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2200 *paudio_only = (bool)disable_overlay;
2202 LOGD("audio_only : %d", *paudio_only);
2206 return MM_ERROR_NONE;
2210 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2212 GList *bucket = element_bucket;
2213 mmplayer_gst_element_t *element = NULL;
2214 mmplayer_gst_element_t *prv_element = NULL;
2215 GstElement *tee_element = NULL;
2216 gint successful_link_count = 0;
2220 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2222 prv_element = (mmplayer_gst_element_t *)bucket->data;
2223 bucket = bucket->next;
2225 for (; bucket; bucket = bucket->next) {
2226 element = (mmplayer_gst_element_t *)bucket->data;
2228 if (element && element->gst) {
2229 if (prv_element && prv_element->gst) {
2230 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2232 prv_element->gst = tee_element;
2234 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2235 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2236 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2240 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2241 LOGD("linking [%s] to [%s] success",
2242 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2243 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2244 successful_link_count++;
2245 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2246 LOGD("keep audio-tee element for next audio pipeline branch");
2247 tee_element = prv_element->gst;
2250 LOGD("linking [%s] to [%s] failed",
2251 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2252 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2258 prv_element = element;
2263 return successful_link_count;
2267 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2269 GList *bucket = element_bucket;
2270 mmplayer_gst_element_t *element = NULL;
2271 int successful_add_count = 0;
2275 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2276 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2278 for (; bucket; bucket = bucket->next) {
2279 element = (mmplayer_gst_element_t *)bucket->data;
2281 if (element && element->gst) {
2282 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2283 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2284 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2285 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2288 successful_add_count++;
2294 return successful_add_count;
2298 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2300 mmplayer_t *player = (mmplayer_t *)data;
2301 GstCaps *caps = NULL;
2302 GstStructure *str = NULL;
2304 gboolean caps_ret = TRUE;
2308 MMPLAYER_RETURN_IF_FAIL(pad);
2309 MMPLAYER_RETURN_IF_FAIL(unused);
2310 MMPLAYER_RETURN_IF_FAIL(data);
2312 caps = gst_pad_get_current_caps(pad);
2316 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2320 LOGD("name = %s", name);
2322 if (strstr(name, "audio")) {
2323 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2325 if (player->audio_stream_changed_cb) {
2326 LOGE("call the audio stream changed cb");
2327 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2329 } else if (strstr(name, "video")) {
2330 if ((name = gst_structure_get_string(str, "format")))
2331 player->set_mode.video_zc = name[0] == 'S';
2333 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2334 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2336 LOGW("invalid caps info");
2341 gst_caps_unref(caps);
2349 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2354 MMPLAYER_RETURN_IF_FAIL(player);
2356 if (player->audio_stream_buff_list) {
2357 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2358 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2361 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2362 __mmplayer_audio_stream_send_data(player, tmp);
2364 MMPLAYER_FREEIF(tmp->pcm_data);
2365 MMPLAYER_FREEIF(tmp);
2368 g_list_free(player->audio_stream_buff_list);
2369 player->audio_stream_buff_list = NULL;
2376 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2378 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2381 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2383 audio_stream.bitrate = a_buffer->bitrate;
2384 audio_stream.channel = a_buffer->channel;
2385 audio_stream.channel_mask = a_buffer->channel_mask;
2386 audio_stream.data_size = a_buffer->data_size;
2387 audio_stream.data = a_buffer->pcm_data;
2388 audio_stream.pcm_format = a_buffer->pcm_format;
2390 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2392 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2398 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2400 mmplayer_t *player = (mmplayer_t *)data;
2401 const gchar *pcm_format = NULL;
2404 guint64 channel_mask = 0;
2405 void *a_data = NULL;
2407 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2408 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2412 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2414 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2415 a_data = mapinfo.data;
2416 a_size = mapinfo.size;
2418 GstCaps *caps = gst_pad_get_current_caps(pad);
2419 GstStructure *structure = gst_caps_get_structure(caps, 0);
2421 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2423 pcm_format = gst_structure_get_string(structure, "format");
2424 gst_structure_get_int(structure, "rate", &rate);
2425 gst_structure_get_int(structure, "channels", &channel);
2426 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2427 gst_caps_unref(GST_CAPS(caps));
2429 /* In case of the sync is false, use buffer list. *
2430 * The num of buffer list depends on the num of audio channels */
2431 if (player->audio_stream_buff_list) {
2432 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2433 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2435 if (channel_mask == tmp->channel_mask) {
2437 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2439 if (tmp->data_size + a_size < tmp->buff_size) {
2440 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2441 tmp->data_size += a_size;
2443 /* send data to client */
2444 __mmplayer_audio_stream_send_data(player, tmp);
2446 if (a_size > tmp->buff_size) {
2447 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2448 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2449 if (tmp->pcm_data == NULL) {
2450 LOGE("failed to realloc data.");
2453 tmp->buff_size = a_size;
2455 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2456 memcpy(tmp->pcm_data, a_data, a_size);
2457 tmp->data_size = a_size;
2462 LOGE("data is empty in list.");
2468 /* create new audio stream data for newly found audio channel */
2469 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2470 if (a_buffer == NULL) {
2471 LOGE("failed to alloc data.");
2474 a_buffer->bitrate = rate;
2475 a_buffer->channel = channel;
2476 a_buffer->channel_mask = channel_mask;
2477 a_buffer->data_size = a_size;
2478 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2480 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2481 /* If sync is FALSE, use buffer list to reduce the IPC. */
2482 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2483 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2484 if (a_buffer->pcm_data == NULL) {
2485 LOGE("failed to alloc data.");
2486 MMPLAYER_FREEIF(a_buffer);
2489 memcpy(a_buffer->pcm_data, a_data, a_size);
2491 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2493 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2495 /* If sync is TRUE, send data directly. */
2496 a_buffer->pcm_data = a_data;
2497 __mmplayer_audio_stream_send_data(player, a_buffer);
2498 MMPLAYER_FREEIF(a_buffer);
2502 gst_buffer_unmap(buffer, &mapinfo);
2507 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2509 mmplayer_t *player = (mmplayer_t *)data;
2510 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2511 GstPad *sinkpad = NULL;
2512 GstElement *queue = NULL, *sink = NULL;
2515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2517 queue = gst_element_factory_make("queue", NULL);
2518 if (queue == NULL) {
2519 LOGD("fail make queue");
2523 sink = gst_element_factory_make("fakesink", NULL);
2525 LOGD("fail make fakesink");
2529 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2531 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2532 LOGW("failed to link queue & sink");
2536 sinkpad = gst_element_get_static_pad(queue, "sink");
2538 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2539 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2543 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2545 gst_object_unref(sinkpad);
2546 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2547 g_object_set(sink, "sync", TRUE, NULL);
2548 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2550 /* keep the first sink reference only */
2551 if (!audiobin[MMPLAYER_A_SINK].gst) {
2552 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2553 audiobin[MMPLAYER_A_SINK].gst = sink;
2557 _mmplayer_add_signal_connection(player,
2559 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2561 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2564 __mmplayer_add_sink(player, sink, FALSE);
2566 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2567 LOGE("failed to sync state");
2571 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2572 LOGE("failed to sync state");
2580 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2582 gst_object_unref(GST_OBJECT(queue));
2586 gst_object_unref(GST_OBJECT(sink));
2590 gst_object_unref(GST_OBJECT(sinkpad));
2598 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2600 mmplayer_t *player = (mmplayer_t *)data;
2603 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2605 player->no_more_pad = TRUE;
2606 _mmplayer_pipeline_complete(NULL, player);
2613 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2615 #define MAX_PROPS_LEN 128
2616 mmplayer_gst_element_t *audiobin = NULL;
2617 gint latency_mode = 0;
2618 gchar *stream_type = NULL;
2619 gchar *latency = NULL;
2621 gchar stream_props[MAX_PROPS_LEN] = {0,};
2622 GstStructure *props = NULL;
2625 * It should be set after player creation through attribute.
2626 * But, it can not be changed during playing.
2629 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2631 audiobin = player->pipeline->audiobin;
2633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2634 if (player->sound.mute) {
2635 LOGD("mute enabled");
2636 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2639 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2640 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2643 snprintf(stream_props, sizeof(stream_props) - 1,
2644 "props,application.process.id.origin=%d", player->client_pid);
2646 snprintf(stream_props, sizeof(stream_props) - 1,
2647 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2648 stream_type, stream_id, player->client_pid);
2650 props = gst_structure_from_string(stream_props, NULL);
2651 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2652 LOGI("props result[%s].", stream_props);
2653 gst_structure_free(props);
2655 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2657 switch (latency_mode) {
2658 case AUDIO_LATENCY_MODE_LOW:
2659 latency = g_strdup("low");
2661 case AUDIO_LATENCY_MODE_MID:
2662 latency = g_strdup("mid");
2664 case AUDIO_LATENCY_MODE_HIGH:
2665 latency = g_strdup("high");
2668 latency = g_strdup("mid");
2672 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2674 LOGD("audiosink property - latency=%s", latency);
2676 MMPLAYER_FREEIF(latency);
2682 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2684 mmplayer_gst_element_t *audiobin = NULL;
2687 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2688 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2690 audiobin = player->pipeline->audiobin;
2692 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2693 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2694 LOGE("failed to create media stream info");
2695 return MM_ERROR_PLAYER_INTERNAL;
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2700 if (player->video360_yaw_radians <= M_PI &&
2701 player->video360_yaw_radians >= -M_PI &&
2702 player->video360_pitch_radians <= M_PI_2 &&
2703 player->video360_pitch_radians >= -M_PI_2) {
2704 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2705 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2706 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2707 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2709 "source-orientation-y", player->video360_metadata.init_view_heading,
2710 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2714 return MM_ERROR_NONE;
2718 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2720 mmplayer_gst_element_t *audiobin = NULL;
2721 GstPad *sink_pad = NULL;
2722 GstCaps *acaps = NULL;
2724 int pitch_control = 0;
2725 double pitch_value = 1.0;
2728 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2729 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2731 audiobin = player->pipeline->audiobin;
2733 LOGD("make element for normal audio playback");
2735 /* audio bin structure for playback. {} means optional.
2736 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2738 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2739 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2742 /* for pitch control */
2743 mm_attrs_multiple_get(player->attrs, NULL,
2744 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2745 MM_PLAYER_PITCH_VALUE, &pitch_value,
2748 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2749 if (pitch_control && (player->videodec_linked == 0)) {
2750 GstElementFactory *factory;
2752 factory = gst_element_factory_find("pitch");
2754 gst_object_unref(factory);
2757 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2760 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2761 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2763 LOGW("there is no pitch element");
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2770 /* replaygain volume */
2771 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2772 if (player->sound.rg_enable)
2773 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2775 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2778 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2780 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2781 /* currently, only openalsink uses volume element */
2782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2783 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2785 if (player->sound.mute) {
2786 LOGD("mute enabled");
2787 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2791 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2793 /* audio effect element. if audio effect is enabled */
2794 if ((strcmp(player->ini.audioeffect_element, ""))
2796 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2797 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2799 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2801 if ((!player->bypass_audio_effect)
2802 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2803 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2804 if (!_mmplayer_audio_effect_custom_apply(player))
2805 LOGI("apply audio effect(custom) setting success");
2809 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2810 && (player->set_mode.rich_audio)) {
2811 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2815 /* create audio sink */
2816 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2817 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2818 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2820 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2821 if (player->is_360_feature_enabled &&
2822 player->is_content_spherical &&
2824 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2825 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2826 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2828 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2832 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2833 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2834 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2835 gst_caps_unref(acaps);
2837 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2839 player->is_openal_plugin_used = TRUE;
2841 if (player->is_360_feature_enabled && player->is_content_spherical)
2842 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2843 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2846 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2847 (player->videodec_linked && player->ini.use_system_clock)) {
2848 LOGD("system clock will be used.");
2849 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2852 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2853 __mmplayer_gst_set_pulsesink_property(player);
2854 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2855 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2860 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2861 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2863 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2864 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2865 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2866 gst_object_unref(GST_OBJECT(sink_pad));
2868 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2871 return MM_ERROR_NONE;
2873 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2875 return MM_ERROR_PLAYER_INTERNAL;
2879 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2881 mmplayer_gst_element_t *audiobin = NULL;
2882 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2884 gchar *dst_format = NULL;
2886 int dst_samplerate = 0;
2887 int dst_channels = 0;
2888 GstCaps *caps = NULL;
2889 char *caps_str = NULL;
2892 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2893 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2895 audiobin = player->pipeline->audiobin;
2897 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2899 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2901 [case 1] extract interleave audio pcm without playback
2902 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2903 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2905 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2907 [case 2] deinterleave for each channel without playback
2908 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2909 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2911 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2912 - fakesink (sync or not)
2915 [case 3] [case 1(sync only)] + playback
2916 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2918 * src - ... - tee - queue1 - playback path
2919 - queue2 - [case1 pipeline with sync]
2921 [case 4] [case 2(sync only)] + playback
2922 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2924 * src - ... - tee - queue1 - playback path
2925 - queue2 - [case2 pipeline with sync]
2929 /* 1. create tee and playback path
2930 'tee' should be added at first to copy the decoded stream
2932 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2933 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2934 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2936 /* tee - path 1 : for playback path */
2937 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2938 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2940 /* tee - path 2 : for extract path */
2941 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2942 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2945 /* if there is tee, 'tee - path 2' is linked here */
2947 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2950 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2952 /* 2. decide the extract pcm format */
2953 mm_attrs_multiple_get(player->attrs, NULL,
2954 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2955 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2956 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2959 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2960 dst_format, dst_len, dst_samplerate, dst_channels);
2962 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2963 mm_attrs_multiple_get(player->attrs, NULL,
2964 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2965 "content_audio_samplerate", &dst_samplerate,
2966 "content_audio_channels", &dst_channels,
2969 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2970 dst_format, dst_len, dst_samplerate, dst_channels);
2972 /* If there is no enough information, set it to platform default value. */
2973 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2974 LOGD("set platform default format");
2975 dst_format = DEFAULT_PCM_OUT_FORMAT;
2977 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2978 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2981 /* 3. create capsfilter */
2982 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2983 caps = gst_caps_new_simple("audio/x-raw",
2984 "format", G_TYPE_STRING, dst_format,
2985 "rate", G_TYPE_INT, dst_samplerate,
2986 "channels", G_TYPE_INT, dst_channels,
2989 caps_str = gst_caps_to_string(caps);
2990 LOGD("new caps : %s", caps_str);
2992 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2995 gst_caps_unref(caps);
2996 MMPLAYER_FREEIF(caps_str);
2998 /* 4-1. create deinterleave to extract pcm for each channel */
2999 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3000 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3001 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3003 /* audiosink will be added after getting signal for each channel */
3004 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3005 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3006 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3007 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3008 player->no_more_pad = FALSE;
3010 /* 4-2. create fakesink to extract interlevaed pcm */
3011 LOGD("add audio fakesink for interleaved audio");
3012 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3013 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3014 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3015 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3017 _mmplayer_add_signal_connection(player,
3018 G_OBJECT(audiobin[extract_sink_id].gst),
3019 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3021 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3024 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3028 return MM_ERROR_NONE;
3030 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3032 return MM_ERROR_PLAYER_INTERNAL;
3036 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3038 int ret = MM_ERROR_NONE;
3039 mmplayer_gst_element_t *audiobin = NULL;
3040 GList *element_bucket = NULL;
3043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3044 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3046 audiobin = player->pipeline->audiobin;
3048 if (player->build_audio_offload) { /* skip all the audio filters */
3049 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3051 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3052 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3053 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3055 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3059 /* FIXME: need to mention the supportable condition at API reference */
3060 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3061 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3063 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3065 if (ret != MM_ERROR_NONE)
3068 LOGD("success to make audio bin element");
3069 *bucket = element_bucket;
3072 return MM_ERROR_NONE;
3075 LOGE("failed to make audio bin element");
3076 g_list_free(element_bucket);
3080 return MM_ERROR_PLAYER_INTERNAL;
3084 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3086 mmplayer_gst_element_t *first_element = NULL;
3087 mmplayer_gst_element_t *audiobin = NULL;
3089 GstPad *ghostpad = NULL;
3090 GList *element_bucket = NULL;
3094 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3097 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3099 LOGE("failed to allocate memory for audiobin");
3100 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3104 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3105 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3106 if (!audiobin[MMPLAYER_A_BIN].gst) {
3107 LOGE("failed to create audiobin");
3112 player->pipeline->audiobin = audiobin;
3114 /* create audio filters and audiosink */
3115 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3118 /* adding created elements to bin */
3119 LOGD("adding created elements to bin");
3120 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3123 /* linking elements in the bucket by added order. */
3124 LOGD("Linking elements in the bucket by added order.");
3125 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3128 /* get first element's sinkpad for creating ghostpad */
3129 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3130 if (!first_element) {
3131 LOGE("failed to get first elem");
3135 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3137 LOGE("failed to get pad from first element of audiobin");
3141 ghostpad = gst_ghost_pad_new("sink", pad);
3143 LOGE("failed to create ghostpad");
3147 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3148 LOGE("failed to add ghostpad to audiobin");
3152 gst_object_unref(pad);
3154 g_list_free(element_bucket);
3157 return MM_ERROR_NONE;
3160 LOGD("ERROR : releasing audiobin");
3163 gst_object_unref(GST_OBJECT(pad));
3166 gst_object_unref(GST_OBJECT(ghostpad));
3169 g_list_free(element_bucket);
3171 /* release element which are not added to bin */
3172 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3173 /* NOTE : skip bin */
3174 if (audiobin[i].gst) {
3175 GstObject *parent = NULL;
3176 parent = gst_element_get_parent(audiobin[i].gst);
3179 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3180 audiobin[i].gst = NULL;
3182 gst_object_unref(GST_OBJECT(parent));
3186 /* release audiobin with it's children */
3187 if (audiobin[MMPLAYER_A_BIN].gst)
3188 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3190 MMPLAYER_FREEIF(audiobin);
3192 player->pipeline->audiobin = NULL;
3194 return MM_ERROR_PLAYER_INTERNAL;
3198 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3200 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3204 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3206 int ret = MM_ERROR_NONE;
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3209 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3211 MMPLAYER_VIDEO_BO_LOCK(player);
3213 if (player->video_bo_list) {
3214 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3215 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3216 if (tmp && tmp->bo == bo) {
3218 LOGD("release bo %p", bo);
3219 tbm_bo_unref(tmp->bo);
3220 MMPLAYER_VIDEO_BO_UNLOCK(player);
3221 MMPLAYER_VIDEO_BO_SIGNAL(player);
3226 /* hw codec is running or the list was reset for DRC. */
3227 LOGW("there is no bo list.");
3229 MMPLAYER_VIDEO_BO_UNLOCK(player);
3231 LOGW("failed to find bo %p", bo);
3235 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3241 tbm_bo_unref(tmp->bo);
3246 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3249 MMPLAYER_RETURN_IF_FAIL(player);
3251 MMPLAYER_VIDEO_BO_LOCK(player);
3252 if (player->video_bo_list) {
3253 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3254 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3255 player->video_bo_list = NULL;
3257 player->video_bo_size = 0;
3258 MMPLAYER_VIDEO_BO_UNLOCK(player);
3265 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3268 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3269 gboolean ret = TRUE;
3271 /* check DRC, if it is, destroy the prev bo list to create again */
3272 if (player->video_bo_size != size) {
3273 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3274 __mmplayer_video_stream_destroy_bo_list(player);
3275 player->video_bo_size = size;
3278 MMPLAYER_VIDEO_BO_LOCK(player);
3280 if ((!player->video_bo_list) ||
3281 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3283 /* create bo list */
3285 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3287 if (player->video_bo_list) {
3288 /* if bo list did not created all, try it again. */
3289 idx = g_list_length(player->video_bo_list);
3290 LOGD("bo list exist(len: %d)", idx);
3293 for (; idx < player->ini.num_of_video_bo; idx++) {
3294 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3296 LOGE("Fail to alloc bo_info.");
3299 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3301 LOGE("Fail to tbm_bo_alloc.");
3302 MMPLAYER_FREEIF(bo_info);
3305 bo_info->used = FALSE;
3306 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3309 /* update video num buffers */
3310 LOGD("video_num_buffers : %d", idx);
3311 mm_player_set_attribute((MMHandleType)player, NULL,
3312 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3313 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3317 MMPLAYER_VIDEO_BO_UNLOCK(player);
3323 /* get bo from list*/
3324 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3325 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3326 if (tmp && (tmp->used == FALSE)) {
3327 LOGD("found bo %p to use", tmp->bo);
3329 MMPLAYER_VIDEO_BO_UNLOCK(player);
3330 return tbm_bo_ref(tmp->bo);
3334 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3335 MMPLAYER_VIDEO_BO_UNLOCK(player);
3339 if (player->ini.video_bo_timeout <= 0) {
3340 MMPLAYER_VIDEO_BO_WAIT(player);
3342 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3343 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3350 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3352 mmplayer_t *player = (mmplayer_t *)data;
3354 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3356 /* send prerolled pkt */
3357 player->video_stream_prerolled = false;
3359 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3361 /* not to send prerolled pkt again */
3362 player->video_stream_prerolled = true;
3366 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3368 mmplayer_t *player = (mmplayer_t *)data;
3369 mmplayer_video_decoded_data_info_t *stream = NULL;
3370 GstMemory *mem = NULL;
3373 MMPLAYER_RETURN_IF_FAIL(player);
3374 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3376 if (player->video_stream_prerolled) {
3377 player->video_stream_prerolled = false;
3378 LOGD("skip the prerolled pkt not to send it again");
3382 /* clear stream data structure */
3383 stream = __mmplayer_create_stream_from_pad(pad);
3385 LOGE("failed to alloc stream");
3389 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3391 /* set size and timestamp */
3392 mem = gst_buffer_peek_memory(buffer, 0);
3393 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3394 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3396 /* check zero-copy */
3397 if (player->set_mode.video_zc &&
3398 player->set_mode.video_export &&
3399 gst_is_tizen_memory(mem)) {
3400 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3401 stream->internal_buffer = gst_buffer_ref(buffer);
3402 } else { /* sw codec */
3403 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3406 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3410 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3411 LOGE("failed to send video decoded data.");
3418 LOGE("release video stream resource.");
3419 if (gst_is_tizen_memory(mem)) {
3421 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3423 tbm_bo_unref(stream->bo[i]);
3426 /* unref gst buffer */
3427 if (stream->internal_buffer)
3428 gst_buffer_unref(stream->internal_buffer);
3431 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3433 MMPLAYER_FREEIF(stream);
3438 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3440 mmplayer_gst_element_t *videobin = NULL;
3443 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3445 videobin = player->pipeline->videobin;
3447 /* Set spatial media metadata and/or user settings to the element.
3449 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3450 "projection-type", player->video360_metadata.projection_type, NULL);
3452 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3453 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3455 if (player->video360_metadata.full_pano_width_pixels &&
3456 player->video360_metadata.full_pano_height_pixels &&
3457 player->video360_metadata.cropped_area_image_width &&
3458 player->video360_metadata.cropped_area_image_height) {
3459 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3460 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3461 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3462 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3463 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3464 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3465 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3469 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3470 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3471 "horizontal-fov", player->video360_horizontal_fov,
3472 "vertical-fov", player->video360_vertical_fov, NULL);
3475 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3476 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3477 "zoom", 1.0f / player->video360_zoom, NULL);
3480 if (player->video360_yaw_radians <= M_PI &&
3481 player->video360_yaw_radians >= -M_PI &&
3482 player->video360_pitch_radians <= M_PI_2 &&
3483 player->video360_pitch_radians >= -M_PI_2) {
3484 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3485 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3486 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3487 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3488 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3489 "pose-yaw", player->video360_metadata.init_view_heading,
3490 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3493 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3494 "passthrough", !player->is_video360_enabled, NULL);
3501 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3503 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3504 GList *element_bucket = NULL;
3507 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3509 /* create video360 filter */
3510 if (player->is_360_feature_enabled && player->is_content_spherical) {
3511 LOGD("create video360 element");
3512 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3513 __mmplayer_gst_set_video360_property(player);
3517 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3518 LOGD("skip creating the videoconv and rotator");
3519 return MM_ERROR_NONE;
3522 /* in case of sw codec & overlay surface type, except 360 playback.
3523 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3524 LOGD("create video converter: %s", video_csc);
3525 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3528 *bucket = element_bucket;
3530 return MM_ERROR_NONE;
3532 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3533 g_list_free(element_bucket);
3537 return MM_ERROR_PLAYER_INTERNAL;
3541 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3543 gchar *factory_name = NULL;
3545 switch (surface_type) {
3546 case MM_DISPLAY_SURFACE_OVERLAY:
3547 if (strlen(player->ini.videosink_element_overlay) > 0)
3548 factory_name = player->ini.videosink_element_overlay;
3550 case MM_DISPLAY_SURFACE_REMOTE:
3551 case MM_DISPLAY_SURFACE_NULL:
3552 if (strlen(player->ini.videosink_element_fake) > 0)
3553 factory_name = player->ini.videosink_element_fake;
3556 LOGE("unidentified surface type");
3560 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3561 return factory_name;
3565 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3567 gchar *factory_name = NULL;
3568 mmplayer_gst_element_t *videobin = NULL;
3573 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3575 videobin = player->pipeline->videobin;
3576 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3578 attrs = MMPLAYER_GET_ATTRS(player);
3580 LOGE("cannot get content attribute");
3581 return MM_ERROR_PLAYER_INTERNAL;
3584 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3585 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3586 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3587 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3588 "use-tbm", use_tbm, NULL);
3591 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3592 return MM_ERROR_PLAYER_INTERNAL;
3594 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3597 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3598 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3601 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3603 LOGD("disable last-sample");
3604 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3607 if (player->set_mode.video_export) {
3609 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3610 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3611 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3613 _mmplayer_add_signal_connection(player,
3614 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3615 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3617 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3620 _mmplayer_add_signal_connection(player,
3621 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3622 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3624 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3628 if (videobin[MMPLAYER_V_SINK].gst) {
3629 GstPad *sink_pad = NULL;
3630 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3632 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3633 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3634 gst_object_unref(GST_OBJECT(sink_pad));
3636 LOGE("failed to get sink pad from videosink");
3640 return MM_ERROR_NONE;
3645 * - video overlay surface(arm/x86) : tizenwlsink
3648 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3651 GList *element_bucket = NULL;
3652 mmplayer_gst_element_t *first_element = NULL;
3653 mmplayer_gst_element_t *videobin = NULL;
3654 gchar *videosink_factory_name = NULL;
3657 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3660 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3662 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3664 player->pipeline->videobin = videobin;
3667 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3668 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3669 if (!videobin[MMPLAYER_V_BIN].gst) {
3670 LOGE("failed to create videobin");
3674 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3677 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3678 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3680 /* additional setting for sink plug-in */
3681 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3682 LOGE("failed to set video property");
3686 /* store it as it's sink element */
3687 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3689 /* adding created elements to bin */
3690 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3691 LOGE("failed to add elements");
3695 /* Linking elements in the bucket by added order */
3696 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3697 LOGE("failed to link elements");
3701 /* get first element's sinkpad for creating ghostpad */
3702 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3703 if (!first_element) {
3704 LOGE("failed to get first element from bucket");
3708 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3710 LOGE("failed to get pad from first element");
3714 /* create ghostpad */
3715 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3716 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3717 LOGE("failed to add ghostpad to videobin");
3720 gst_object_unref(pad);
3722 /* done. free allocated variables */
3723 g_list_free(element_bucket);
3727 return MM_ERROR_NONE;
3730 LOGE("ERROR : releasing videobin");
3731 g_list_free(element_bucket);
3734 gst_object_unref(GST_OBJECT(pad));
3736 /* release videobin with it's children */
3737 if (videobin[MMPLAYER_V_BIN].gst)
3738 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3740 MMPLAYER_FREEIF(videobin);
3741 player->pipeline->videobin = NULL;
3743 return MM_ERROR_PLAYER_INTERNAL;
3747 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3749 GList *element_bucket = NULL;
3750 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3752 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3753 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3754 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3755 "signal-handoffs", FALSE,
3758 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3759 _mmplayer_add_signal_connection(player,
3760 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3761 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3763 G_CALLBACK(__mmplayer_update_subtitle),
3766 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3767 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3769 if (!player->play_subtitle) {
3770 LOGD("add textbin sink as sink element of whole pipeline.");
3771 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3774 /* adding created elements to bin */
3775 LOGD("adding created elements to bin");
3776 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3777 LOGE("failed to add elements");
3781 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3782 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3783 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3785 /* linking elements in the bucket by added order. */
3786 LOGD("Linking elements in the bucket by added order.");
3787 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3788 LOGE("failed to link elements");
3792 /* done. free allocated variables */
3793 g_list_free(element_bucket);
3795 if (textbin[MMPLAYER_T_QUEUE].gst) {
3797 GstPad *ghostpad = NULL;
3799 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3801 LOGE("failed to get sink pad of text queue");
3805 ghostpad = gst_ghost_pad_new("text_sink", pad);
3806 gst_object_unref(pad);
3809 LOGE("failed to create ghostpad of textbin");
3813 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3814 LOGE("failed to add ghostpad to textbin");
3815 gst_object_unref(ghostpad);
3820 return MM_ERROR_NONE;
3823 g_list_free(element_bucket);
3825 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3826 LOGE("remove textbin sink from sink list");
3827 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3830 /* release element at __mmplayer_gst_create_text_sink_bin */
3831 return MM_ERROR_PLAYER_INTERNAL;
3835 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3837 mmplayer_gst_element_t *textbin = NULL;
3838 GList *element_bucket = NULL;
3839 int surface_type = 0;
3844 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3847 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3849 LOGE("failed to allocate memory for textbin");
3850 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3854 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3855 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3856 if (!textbin[MMPLAYER_T_BIN].gst) {
3857 LOGE("failed to create textbin");
3862 player->pipeline->textbin = textbin;
3865 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3866 LOGD("surface type for subtitle : %d", surface_type);
3867 switch (surface_type) {
3868 case MM_DISPLAY_SURFACE_OVERLAY:
3869 case MM_DISPLAY_SURFACE_NULL:
3870 case MM_DISPLAY_SURFACE_REMOTE:
3871 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3872 LOGE("failed to make plain text elements");
3883 return MM_ERROR_NONE;
3887 LOGD("ERROR : releasing textbin");
3889 g_list_free(element_bucket);
3891 /* release signal */
3892 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3894 /* release element which are not added to bin */
3895 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3896 /* NOTE : skip bin */
3897 if (textbin[i].gst) {
3898 GstObject *parent = NULL;
3899 parent = gst_element_get_parent(textbin[i].gst);
3902 gst_object_unref(GST_OBJECT(textbin[i].gst));
3903 textbin[i].gst = NULL;
3905 gst_object_unref(GST_OBJECT(parent));
3910 /* release textbin with it's children */
3911 if (textbin[MMPLAYER_T_BIN].gst)
3912 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3914 MMPLAYER_FREEIF(textbin);
3915 player->pipeline->textbin = NULL;
3918 return MM_ERROR_PLAYER_INTERNAL;
3922 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3924 mmplayer_gst_element_t *mainbin = NULL;
3925 mmplayer_gst_element_t *textbin = NULL;
3926 MMHandleType attrs = 0;
3927 GstElement *subsrc = NULL;
3928 GstElement *subparse = NULL;
3929 gchar *subtitle_uri = NULL;
3930 const gchar *charset = NULL;
3936 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3938 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3940 mainbin = player->pipeline->mainbin;
3942 attrs = MMPLAYER_GET_ATTRS(player);
3944 LOGE("cannot get content attribute");
3945 return MM_ERROR_PLAYER_INTERNAL;
3948 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3949 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3950 LOGE("subtitle uri is not proper filepath.");
3951 return MM_ERROR_PLAYER_INVALID_URI;
3954 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3955 LOGE("failed to get storage info of subtitle path");
3956 return MM_ERROR_PLAYER_INVALID_URI;
3959 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3961 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3962 player->subtitle_language_list = NULL;
3963 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3965 /* create the subtitle source */
3966 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3968 LOGE("failed to create filesrc element");
3971 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3973 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3974 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3976 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3977 LOGW("failed to add queue");
3978 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3979 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3980 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3985 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3987 LOGE("failed to create subparse element");
3991 charset = _mmplayer_get_charset(subtitle_uri);
3993 LOGD("detected charset is %s", charset);
3994 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3997 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3998 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4000 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4001 LOGW("failed to add subparse");
4002 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4003 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4004 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4008 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4009 LOGW("failed to link subsrc and subparse");
4013 player->play_subtitle = TRUE;
4014 player->adjust_subtitle_pos = 0;
4016 LOGD("play subtitle using subtitle file");
4018 if (player->pipeline->textbin == NULL) {
4019 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4020 LOGE("failed to create text sink bin. continuing without text");
4024 textbin = player->pipeline->textbin;
4026 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4027 LOGW("failed to add textbin");
4029 /* release signal */
4030 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4032 /* release textbin with it's children */
4033 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4034 MMPLAYER_FREEIF(player->pipeline->textbin);
4035 player->pipeline->textbin = textbin = NULL;
4039 LOGD("link text input selector and textbin ghost pad");
4041 player->textsink_linked = 1;
4042 player->external_text_idx = 0;
4043 LOGI("textsink is linked");
4045 textbin = player->pipeline->textbin;
4046 LOGD("text bin has been created. reuse it.");
4047 player->external_text_idx = 1;
4050 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4051 LOGW("failed to link subparse and textbin");
4055 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4057 LOGE("failed to get sink pad from textsink to probe data");
4061 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4062 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4064 gst_object_unref(pad);
4067 /* create dot. for debugging */
4068 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4071 return MM_ERROR_NONE;
4074 /* release text pipeline resource */
4075 player->textsink_linked = 0;
4077 /* release signal */
4078 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4080 if (player->pipeline->textbin) {
4081 LOGE("remove textbin");
4083 /* release textbin with it's children */
4084 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4085 MMPLAYER_FREEIF(player->pipeline->textbin);
4086 player->pipeline->textbin = NULL;
4090 /* release subtitle elem */
4091 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4092 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4094 return MM_ERROR_PLAYER_INTERNAL;
4098 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4100 mmplayer_t *player = (mmplayer_t *)data;
4101 MMMessageParamType msg = {0, };
4102 GstClockTime duration = 0;
4103 gpointer text = NULL;
4104 guint text_size = 0;
4105 gboolean ret = TRUE;
4106 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4110 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4111 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4113 if (player->is_subtitle_force_drop) {
4114 LOGW("subtitle is dropped forcedly.");
4118 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4119 text = mapinfo.data;
4120 text_size = mapinfo.size;
4122 if (player->set_mode.subtitle_off) {
4123 LOGD("subtitle is OFF.");
4127 if (!text || (text_size == 0)) {
4128 LOGD("There is no subtitle to be displayed.");
4132 msg.data = (void *)text;
4134 duration = GST_BUFFER_DURATION(buffer);
4136 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4137 if (player->duration > GST_BUFFER_PTS(buffer))
4138 duration = player->duration - GST_BUFFER_PTS(buffer);
4141 LOGI("subtitle duration is invalid, subtitle duration change "
4142 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4144 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4146 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4148 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4149 gst_buffer_unmap(buffer, &mapinfo);
4156 static GstPadProbeReturn
4157 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4159 mmplayer_t *player = (mmplayer_t *)u_data;
4160 GstClockTime cur_timestamp = 0;
4161 gint64 adjusted_timestamp = 0;
4162 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4164 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4166 if (player->set_mode.subtitle_off) {
4167 LOGD("subtitle is OFF.");
4171 if (player->adjust_subtitle_pos == 0) {
4172 LOGD("nothing to do");
4176 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4177 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4179 if (adjusted_timestamp < 0) {
4180 LOGD("adjusted_timestamp under zero");
4185 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4186 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4187 GST_TIME_ARGS(cur_timestamp),
4188 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4190 return GST_PAD_PROBE_OK;
4194 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4198 /* check player and subtitlebin are created */
4199 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4200 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4202 if (position == 0) {
4203 LOGD("nothing to do");
4205 return MM_ERROR_NONE;
4208 /* check current position */
4209 player->adjust_subtitle_pos = position;
4211 LOGD("save adjust_subtitle_pos in player");
4215 return MM_ERROR_NONE;
4219 * This function is to create audio or video pipeline for playing.
4221 * @param player [in] handle of player
4223 * @return This function returns zero on success.
4228 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4230 int ret = MM_ERROR_NONE;
4231 mmplayer_gst_element_t *mainbin = NULL;
4232 MMHandleType attrs = 0;
4235 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4237 /* get profile attribute */
4238 attrs = MMPLAYER_GET_ATTRS(player);
4240 LOGE("failed to get content attribute");
4244 /* create pipeline handles */
4245 if (player->pipeline) {
4246 LOGE("pipeline should be released before create new one");
4250 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4252 /* create mainbin */
4253 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4254 if (mainbin == NULL)
4257 /* create pipeline */
4258 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4259 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4260 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4261 LOGE("failed to create pipeline");
4266 player->pipeline->mainbin = mainbin;
4268 /* create the source and decoder elements */
4269 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4270 ret = _mmplayer_gst_build_es_pipeline(player);
4272 if (MMPLAYER_USE_DECODEBIN(player))
4273 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4275 ret = _mmplayer_gst_build_pipeline_with_src(player);
4278 if (ret != MM_ERROR_NONE) {
4279 LOGE("failed to create some elements");
4283 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4284 if (__mmplayer_check_subtitle(player)
4285 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4286 LOGE("failed to create text pipeline");
4289 ret = _mmplayer_gst_add_bus_watch(player);
4290 if (ret != MM_ERROR_NONE) {
4291 LOGE("failed to add bus watch");
4296 return MM_ERROR_NONE;
4299 _mmplayer_bus_watcher_remove(player);
4300 __mmplayer_gst_destroy_pipeline(player);
4301 return MM_ERROR_PLAYER_INTERNAL;
4305 __mmplayer_reset_gapless_state(mmplayer_t *player)
4308 MMPLAYER_RETURN_IF_FAIL(player
4310 && player->pipeline->audiobin
4311 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4313 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4320 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4323 int ret = MM_ERROR_NONE;
4327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4329 /* cleanup stuffs */
4330 MMPLAYER_FREEIF(player->type);
4331 player->no_more_pad = FALSE;
4332 player->num_dynamic_pad = 0;
4334 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4335 player->subtitle_language_list = NULL;
4336 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4338 MMPLAYER_RECONFIGURE_LOCK(player);
4339 __mmplayer_reset_gapless_state(player);
4340 MMPLAYER_RECONFIGURE_UNLOCK(player);
4342 if (player->streamer) {
4343 _mm_player_streaming_initialize(player->streamer, FALSE);
4344 _mm_player_streaming_destroy(player->streamer);
4345 player->streamer = NULL;
4348 /* cleanup unlinked mime type */
4349 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4350 MMPLAYER_FREEIF(player->unlinked_video_mime);
4351 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4353 /* cleanup running stuffs */
4354 _mmplayer_cancel_eos_timer(player);
4356 /* cleanup gst stuffs */
4357 if (player->pipeline) {
4358 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4359 GstTagList *tag_list = player->pipeline->tag_list;
4361 /* first we need to disconnect all signal hander */
4362 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4365 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4366 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4367 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4368 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4369 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4370 gst_object_unref(bus);
4372 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4373 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4374 if (ret != MM_ERROR_NONE) {
4375 LOGE("fail to change state to NULL");
4376 return MM_ERROR_PLAYER_INTERNAL;
4379 LOGW("succeeded in changing state to NULL");
4381 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4384 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4385 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4387 MMPLAYER_FREEIF(audiobin);
4388 MMPLAYER_FREEIF(videobin);
4389 MMPLAYER_FREEIF(textbin);
4390 MMPLAYER_FREEIF(mainbin);
4394 gst_tag_list_unref(tag_list);
4396 MMPLAYER_FREEIF(player->pipeline);
4398 MMPLAYER_FREEIF(player->album_art);
4400 if (player->type_caps) {
4401 gst_caps_unref(player->type_caps);
4402 player->type_caps = NULL;
4405 if (player->v_stream_caps) {
4406 gst_caps_unref(player->v_stream_caps);
4407 player->v_stream_caps = NULL;
4410 if (player->a_stream_caps) {
4411 gst_caps_unref(player->a_stream_caps);
4412 player->a_stream_caps = NULL;
4415 if (player->s_stream_caps) {
4416 gst_caps_unref(player->s_stream_caps);
4417 player->s_stream_caps = NULL;
4419 _mmplayer_track_destroy(player);
4421 if (player->sink_elements)
4422 g_list_free(player->sink_elements);
4423 player->sink_elements = NULL;
4425 if (player->bufmgr) {
4426 tbm_bufmgr_deinit(player->bufmgr);
4427 player->bufmgr = NULL;
4430 LOGW("finished destroy pipeline");
4438 __mmplayer_gst_realize(mmplayer_t *player)
4441 int ret = MM_ERROR_NONE;
4445 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4447 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4449 ret = __mmplayer_gst_create_pipeline(player);
4451 LOGE("failed to create pipeline");
4455 /* set pipeline state to READY */
4456 /* NOTE : state change to READY must be performed sync. */
4457 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4458 ret = _mmplayer_gst_set_state(player,
4459 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4461 if (ret != MM_ERROR_NONE) {
4462 /* return error if failed to set state */
4463 LOGE("failed to set READY state");
4467 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4469 /* create dot before error-return. for debugging */
4470 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4478 __mmplayer_gst_unrealize(mmplayer_t *player)
4480 int ret = MM_ERROR_NONE;
4484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4486 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4487 MMPLAYER_PRINT_STATE(player);
4489 /* release miscellaneous information */
4490 __mmplayer_release_misc(player);
4492 /* destroy pipeline */
4493 ret = __mmplayer_gst_destroy_pipeline(player);
4494 if (ret != MM_ERROR_NONE) {
4495 LOGE("failed to destroy pipeline");
4499 /* release miscellaneous information.
4500 these info needs to be released after pipeline is destroyed. */
4501 __mmplayer_release_misc_post(player);
4503 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4511 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4516 LOGW("set_message_callback is called with invalid player handle");
4517 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4520 player->msg_cb = callback;
4521 player->msg_cb_param = user_param;
4523 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4527 return MM_ERROR_NONE;
4531 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4533 int ret = MM_ERROR_NONE;
4538 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4539 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4540 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4542 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4544 if (strstr(uri, "es_buff://")) {
4545 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4546 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4547 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4548 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4550 tmp = g_ascii_strdown(uri, strlen(uri));
4551 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4552 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4554 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4556 } else if (strstr(uri, "mms://")) {
4557 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4558 } else if ((path = strstr(uri, "mem://"))) {
4559 ret = __mmplayer_set_mem_uri(data, path, param);
4561 ret = __mmplayer_set_file_uri(data, uri);
4564 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4565 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4566 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4567 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4569 /* dump parse result */
4570 SECURE_LOGW("incoming uri : %s", uri);
4571 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4572 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4580 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4583 mmplayer_t *player = NULL;
4584 MMMessageParamType msg = {0, };
4586 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4591 LOGE("user_data is null");
4595 player = (mmplayer_t *)user_data;
4597 if (!player->pipeline || !player->attrs) {
4598 LOGW("not initialized");
4602 LOGD("cmd lock player, cmd state : %d", player->cmd);
4603 MMPLAYER_CMD_LOCK(player);
4604 LOGD("cmd locked player");
4606 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4607 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4608 LOGW("player already destroyed");
4609 MMPLAYER_CMD_UNLOCK(player);
4613 player->interrupted_by_resource = TRUE;
4615 /* get last play position */
4616 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4617 msg.union_type = MM_MSG_UNION_TIME;
4618 msg.time.elapsed = pos;
4619 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4621 LOGW("failed to get play position.");
4624 LOGD("video resource conflict so, resource will be freed by unrealizing");
4625 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4626 LOGE("failed to unrealize");
4628 MMPLAYER_CMD_UNLOCK(player);
4630 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4631 player->hw_resource[res_idx] = NULL;
4635 return TRUE; /* release all the resources */
4639 __mmplayer_initialize_video_roi(mmplayer_t *player)
4641 player->video_roi.scale_x = 0.0;
4642 player->video_roi.scale_y = 0.0;
4643 player->video_roi.scale_width = 1.0;
4644 player->video_roi.scale_height = 1.0;
4648 _mmplayer_create_player(MMHandleType handle)
4650 int ret = MM_ERROR_PLAYER_INTERNAL;
4651 bool enabled = false;
4653 mmplayer_t *player = MM_PLAYER_CAST(handle);
4657 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4659 /* initialize player state */
4660 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4661 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4662 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4663 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4665 /* check current state */
4666 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4668 /* construct attributes */
4669 player->attrs = _mmplayer_construct_attribute(handle);
4671 if (!player->attrs) {
4672 LOGE("Failed to construct attributes");
4676 /* initialize gstreamer with configured parameter */
4677 if (!__mmplayer_init_gstreamer(player)) {
4678 LOGE("Initializing gstreamer failed");
4679 _mmplayer_deconstruct_attribute(handle);
4683 /* create lock. note that g_tread_init() has already called in gst_init() */
4684 g_mutex_init(&player->fsink_lock);
4686 /* create update tag lock */
4687 g_mutex_init(&player->update_tag_lock);
4689 /* create gapless play mutex */
4690 g_mutex_init(&player->gapless_play_thread_mutex);
4692 /* create gapless play cond */
4693 g_cond_init(&player->gapless_play_thread_cond);
4695 /* create gapless play thread */
4696 player->gapless_play_thread =
4697 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4698 if (!player->gapless_play_thread) {
4699 LOGE("failed to create gapless play thread");
4700 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4701 g_mutex_clear(&player->gapless_play_thread_mutex);
4702 g_cond_clear(&player->gapless_play_thread_cond);
4706 player->bus_msg_q = g_queue_new();
4707 if (!player->bus_msg_q) {
4708 LOGE("failed to create queue for bus_msg");
4709 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4713 ret = _mmplayer_initialize_video_capture(player);
4714 if (ret != MM_ERROR_NONE) {
4715 LOGE("failed to initialize video capture");
4719 /* initialize resource manager */
4720 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4721 __resource_release_cb, player, &player->resource_manager)
4722 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4723 LOGE("failed to create resource manager");
4724 ret = MM_ERROR_PLAYER_INTERNAL;
4728 /* create video bo lock and cond */
4729 g_mutex_init(&player->video_bo_mutex);
4730 g_cond_init(&player->video_bo_cond);
4732 /* create subtitle info lock and cond */
4733 g_mutex_init(&player->subtitle_info_mutex);
4734 g_cond_init(&player->subtitle_info_cond);
4736 player->streaming_type = STREAMING_SERVICE_NONE;
4738 /* give default value of audio effect setting */
4739 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4740 player->sound.rg_enable = false;
4741 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4743 player->play_subtitle = FALSE;
4744 player->has_closed_caption = FALSE;
4745 player->pending_resume = FALSE;
4746 if (player->ini.dump_element_keyword[0][0] == '\0')
4747 player->ini.set_dump_element_flag = FALSE;
4749 player->ini.set_dump_element_flag = TRUE;
4751 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4752 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4753 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4755 /* Set video360 settings to their defaults for just-created player.
4758 player->is_360_feature_enabled = FALSE;
4759 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4760 LOGI("spherical feature info: %d", enabled);
4762 player->is_360_feature_enabled = TRUE;
4764 LOGE("failed to get spherical feature info");
4767 player->is_content_spherical = FALSE;
4768 player->is_video360_enabled = TRUE;
4769 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4770 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4771 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4772 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4773 player->video360_zoom = 1.0f;
4774 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4775 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4777 __mmplayer_initialize_video_roi(player);
4779 /* set player state to null */
4780 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4781 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4785 return MM_ERROR_NONE;
4789 g_mutex_clear(&player->fsink_lock);
4790 /* free update tag lock */
4791 g_mutex_clear(&player->update_tag_lock);
4792 g_queue_free(player->bus_msg_q);
4793 player->bus_msg_q = NULL;
4794 /* free gapless play thread */
4795 if (player->gapless_play_thread) {
4796 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4797 player->gapless_play_thread_exit = TRUE;
4798 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4799 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4801 g_thread_join(player->gapless_play_thread);
4802 player->gapless_play_thread = NULL;
4804 g_mutex_clear(&player->gapless_play_thread_mutex);
4805 g_cond_clear(&player->gapless_play_thread_cond);
4808 /* release attributes */
4809 _mmplayer_deconstruct_attribute(handle);
4817 __mmplayer_init_gstreamer(mmplayer_t *player)
4819 static gboolean initialized = FALSE;
4820 static const int max_argc = 50;
4822 gchar **argv = NULL;
4823 gchar **argv2 = NULL;
4829 LOGD("gstreamer already initialized.");
4834 argc = malloc(sizeof(int));
4835 argv = malloc(sizeof(gchar *) * max_argc);
4836 argv2 = malloc(sizeof(gchar *) * max_argc);
4838 if (!argc || !argv || !argv2)
4841 memset(argv, 0, sizeof(gchar *) * max_argc);
4842 memset(argv2, 0, sizeof(gchar *) * max_argc);
4846 argv[0] = g_strdup("mmplayer");
4849 for (i = 0; i < 5; i++) {
4850 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4851 if (strlen(player->ini.gst_param[i]) > 0) {
4852 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4857 /* we would not do fork for scanning plugins */
4858 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4861 /* check disable registry scan */
4862 if (player->ini.skip_rescan) {
4863 argv[*argc] = g_strdup("--gst-disable-registry-update");
4867 /* check disable segtrap */
4868 if (player->ini.disable_segtrap) {
4869 argv[*argc] = g_strdup("--gst-disable-segtrap");
4873 LOGD("initializing gstreamer with following parameter");
4874 LOGD("argc : %d", *argc);
4877 for (i = 0; i < arg_count; i++) {
4879 LOGD("argv[%d] : %s", i, argv2[i]);
4882 /* initializing gstreamer */
4883 if (!gst_init_check(argc, &argv, &err)) {
4884 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4891 for (i = 0; i < arg_count; i++) {
4893 LOGD("release - argv[%d] : %s", i, argv2[i]);
4895 MMPLAYER_FREEIF(argv2[i]);
4898 MMPLAYER_FREEIF(argv);
4899 MMPLAYER_FREEIF(argv2);
4900 MMPLAYER_FREEIF(argc);
4910 for (i = 0; i < arg_count; i++) {
4911 LOGD("free[%d] : %s", i, argv2[i]);
4912 MMPLAYER_FREEIF(argv2[i]);
4915 MMPLAYER_FREEIF(argv);
4916 MMPLAYER_FREEIF(argv2);
4917 MMPLAYER_FREEIF(argc);
4923 __mmplayer_check_async_state_transition(mmplayer_t *player)
4925 GstState element_state = GST_STATE_VOID_PENDING;
4926 GstState element_pending_state = GST_STATE_VOID_PENDING;
4927 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4928 GstElement *element = NULL;
4929 gboolean async = FALSE;
4931 /* check player handle */
4932 MMPLAYER_RETURN_IF_FAIL(player &&
4934 player->pipeline->mainbin &&
4935 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4938 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4940 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4941 LOGD("don't need to check the pipeline state");
4945 MMPLAYER_PRINT_STATE(player);
4947 /* wait for state transition */
4948 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4949 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4951 if (ret == GST_STATE_CHANGE_FAILURE) {
4952 LOGE(" [%s] state : %s pending : %s",
4953 GST_ELEMENT_NAME(element),
4954 gst_element_state_get_name(element_state),
4955 gst_element_state_get_name(element_pending_state));
4957 /* dump state of all element */
4958 _mmplayer_dump_pipeline_state(player);
4963 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4968 _mmplayer_destroy(MMHandleType handle)
4970 mmplayer_t *player = MM_PLAYER_CAST(handle);
4974 /* check player handle */
4975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4977 /* destroy can called at anytime */
4978 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4980 /* check async state transition */
4981 __mmplayer_check_async_state_transition(player);
4983 /* release gapless play thread */
4984 if (player->gapless_play_thread) {
4985 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4986 player->gapless_play_thread_exit = TRUE;
4987 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4988 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4990 LOGD("waiting for gapless play thread exit");
4991 g_thread_join(player->gapless_play_thread);
4992 g_mutex_clear(&player->gapless_play_thread_mutex);
4993 g_cond_clear(&player->gapless_play_thread_cond);
4994 LOGD("gapless play thread released");
4997 _mmplayer_release_video_capture(player);
4999 /* release miscellaneous information */
5000 __mmplayer_release_misc(player);
5002 /* release pipeline */
5003 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5004 LOGE("failed to destroy pipeline");
5005 return MM_ERROR_PLAYER_INTERNAL;
5008 __mmplayer_destroy_hw_resource(player);
5010 g_queue_free(player->bus_msg_q);
5012 /* release subtitle info lock and cond */
5013 g_mutex_clear(&player->subtitle_info_mutex);
5014 g_cond_clear(&player->subtitle_info_cond);
5016 __mmplayer_release_dump_list(player->dump_list);
5018 /* release miscellaneous information.
5019 these info needs to be released after pipeline is destroyed. */
5020 __mmplayer_release_misc_post(player);
5022 /* release attributes */
5023 _mmplayer_deconstruct_attribute(handle);
5025 if (player->uri_info.uri_list) {
5026 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5027 player->uri_info.uri_list = NULL;
5031 g_mutex_clear(&player->fsink_lock);
5034 g_mutex_clear(&player->update_tag_lock);
5036 /* release video bo lock and cond */
5037 g_mutex_clear(&player->video_bo_mutex);
5038 g_cond_clear(&player->video_bo_cond);
5042 return MM_ERROR_NONE;
5046 _mmplayer_realize(MMHandleType hplayer)
5048 mmplayer_t *player = (mmplayer_t *)hplayer;
5049 int ret = MM_ERROR_NONE;
5052 MMHandleType attrs = 0;
5056 /* check player handle */
5057 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5059 /* check current state */
5060 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5062 attrs = MMPLAYER_GET_ATTRS(player);
5064 LOGE("fail to get attributes.");
5065 return MM_ERROR_PLAYER_INTERNAL;
5067 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5068 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5070 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5071 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5073 if (ret != MM_ERROR_NONE) {
5074 LOGE("failed to parse profile");
5079 if (uri && (strstr(uri, "es_buff://"))) {
5080 if (strstr(uri, "es_buff://push_mode"))
5081 player->es_player_push_mode = TRUE;
5083 player->es_player_push_mode = FALSE;
5086 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5087 LOGW("mms protocol is not supported format.");
5088 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5091 if (MMPLAYER_IS_STREAMING(player))
5092 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5094 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5096 player->smooth_streaming = FALSE;
5097 player->videodec_linked = 0;
5098 player->audiodec_linked = 0;
5099 player->textsink_linked = 0;
5100 player->is_external_subtitle_present = FALSE;
5101 player->is_external_subtitle_added_now = FALSE;
5102 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5103 player->video360_metadata.is_spherical = -1;
5104 player->is_openal_plugin_used = FALSE;
5105 player->subtitle_language_list = NULL;
5106 player->is_subtitle_force_drop = FALSE;
5108 _mmplayer_track_initialize(player);
5109 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5111 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5112 gint prebuffer_ms = 0, rebuffer_ms = 0;
5114 player->streamer = _mm_player_streaming_create();
5115 _mm_player_streaming_initialize(player->streamer, TRUE);
5117 mm_attrs_multiple_get(player->attrs, NULL,
5118 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5119 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5121 if (prebuffer_ms > 0) {
5122 prebuffer_ms = MAX(prebuffer_ms, 1000);
5123 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5126 if (rebuffer_ms > 0) {
5127 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5128 rebuffer_ms = MAX(rebuffer_ms, 1000);
5129 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5132 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5133 player->streamer->buffering_req.rebuffer_time);
5136 /* realize pipeline */
5137 ret = __mmplayer_gst_realize(player);
5138 if (ret != MM_ERROR_NONE)
5139 LOGE("fail to realize the player.");
5141 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5149 _mmplayer_unrealize(MMHandleType hplayer)
5151 mmplayer_t *player = (mmplayer_t *)hplayer;
5152 int ret = MM_ERROR_NONE;
5153 int rm_ret = MM_ERROR_NONE;
5154 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5160 MMPLAYER_CMD_UNLOCK(player);
5161 _mmplayer_bus_watcher_remove(player);
5162 /* destroy the gst bus msg thread which is created during realize.
5163 this funct have to be called before getting cmd lock. */
5164 _mmplayer_bus_msg_thread_destroy(player);
5165 MMPLAYER_CMD_LOCK(player);
5167 /* check current state */
5168 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5170 /* check async state transition */
5171 __mmplayer_check_async_state_transition(player);
5173 /* unrealize pipeline */
5174 ret = __mmplayer_gst_unrealize(player);
5176 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5177 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5178 if (rm_ret != MM_ERROR_NONE)
5179 LOGE("failed to release [%d] resources", res_idx);
5182 player->interrupted_by_resource = FALSE;
5189 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5191 mmplayer_t *player = (mmplayer_t *)hplayer;
5193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5195 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5199 _mmplayer_get_state(MMHandleType hplayer, int *state)
5201 mmplayer_t *player = (mmplayer_t *)hplayer;
5203 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5205 *state = MMPLAYER_CURRENT_STATE(player);
5207 return MM_ERROR_NONE;
5211 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5213 GstElement *vol_element = NULL;
5214 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5218 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5220 /* check pipeline handle */
5221 if (!player->pipeline || !player->pipeline->audiobin) {
5222 LOGD("'%s' will be applied when audiobin is created", prop_name);
5224 /* NOTE : stored value will be used in create_audiobin
5225 * returning MM_ERROR_NONE here makes application to able to
5226 * set audio volume or mute at anytime.
5228 return MM_ERROR_NONE;
5231 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5232 volume_elem_id = MMPLAYER_A_SINK;
5234 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5236 LOGE("failed to get vol element %d", volume_elem_id);
5237 return MM_ERROR_PLAYER_INTERNAL;
5240 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5242 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5243 LOGE("there is no '%s' property", prop_name);
5244 return MM_ERROR_PLAYER_INTERNAL;
5247 if (!strcmp(prop_name, "volume")) {
5248 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5249 } else if (!strcmp(prop_name, "mute")) {
5250 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5252 LOGE("invalid property %s", prop_name);
5253 return MM_ERROR_PLAYER_INTERNAL;
5256 return MM_ERROR_NONE;
5260 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5262 int ret = MM_ERROR_NONE;
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268 LOGD("volume = %f", volume);
5270 /* invalid factor range or not */
5271 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5272 LOGE("Invalid volume value");
5273 return MM_ERROR_INVALID_ARGUMENT;
5276 player->sound.volume = volume;
5278 ret = __mmplayer_gst_set_volume_property(player, "volume");
5285 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5287 mmplayer_t *player = (mmplayer_t *)hplayer;
5291 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5294 *volume = player->sound.volume;
5296 LOGD("current vol = %f", *volume);
5299 return MM_ERROR_NONE;
5303 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5305 int ret = MM_ERROR_NONE;
5306 mmplayer_t *player = (mmplayer_t *)hplayer;
5309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5311 LOGD("mute = %d", mute);
5313 player->sound.mute = mute;
5315 ret = __mmplayer_gst_set_volume_property(player, "mute");
5322 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5324 mmplayer_t *player = (mmplayer_t *)hplayer;
5328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5329 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5331 *mute = player->sound.mute;
5333 LOGD("current mute = %d", *mute);
5337 return MM_ERROR_NONE;
5341 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5343 mmplayer_t *player = (mmplayer_t *)hplayer;
5347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5349 player->audio_stream_changed_cb = callback;
5350 player->audio_stream_changed_cb_user_param = user_param;
5351 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5355 return MM_ERROR_NONE;
5359 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5361 mmplayer_t *player = (mmplayer_t *)hplayer;
5365 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5367 player->audio_decoded_cb = callback;
5368 player->audio_decoded_cb_user_param = user_param;
5369 player->audio_extract_opt = opt;
5370 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5374 return MM_ERROR_NONE;
5378 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5380 mmplayer_t *player = (mmplayer_t *)hplayer;
5384 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5386 if (callback && !player->bufmgr)
5387 player->bufmgr = tbm_bufmgr_init(-1);
5389 player->set_mode.video_export = (callback) ? true : false;
5390 player->video_decoded_cb = callback;
5391 player->video_decoded_cb_user_param = user_param;
5393 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5397 return MM_ERROR_NONE;
5401 _mmplayer_start(MMHandleType hplayer)
5403 mmplayer_t *player = (mmplayer_t *)hplayer;
5404 gint ret = MM_ERROR_NONE;
5408 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5410 /* check current state */
5411 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5413 /* start pipeline */
5414 ret = _mmplayer_gst_start(player);
5415 if (ret != MM_ERROR_NONE)
5416 LOGE("failed to start player.");
5418 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5419 LOGD("force playing start even during buffering");
5420 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5428 /* NOTE: post "not supported codec message" to application
5429 * when one codec is not found during AUTOPLUGGING in MSL.
5430 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5431 * And, if any codec is not found, don't send message here.
5432 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5435 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5437 MMMessageParamType msg_param;
5438 memset(&msg_param, 0, sizeof(MMMessageParamType));
5439 gboolean post_msg_direct = FALSE;
5443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5445 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5446 player->not_supported_codec, player->can_support_codec);
5448 if (player->not_found_demuxer) {
5449 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5450 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5452 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5453 MMPLAYER_FREEIF(msg_param.data);
5455 return MM_ERROR_NONE;
5458 if (player->not_supported_codec) {
5459 if (player->can_support_codec) {
5460 // There is one codec to play
5461 post_msg_direct = TRUE;
5463 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5464 post_msg_direct = TRUE;
5467 if (post_msg_direct) {
5468 MMMessageParamType msg_param;
5469 memset(&msg_param, 0, sizeof(MMMessageParamType));
5471 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5472 LOGW("not found AUDIO codec, posting error code to application.");
5474 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5475 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5476 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5477 LOGW("not found VIDEO codec, posting error code to application.");
5479 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5480 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5483 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5485 MMPLAYER_FREEIF(msg_param.data);
5487 return MM_ERROR_NONE;
5489 // no any supported codec case
5490 LOGW("not found any codec, posting error code to application.");
5492 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5493 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5494 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5496 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5497 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5500 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5502 MMPLAYER_FREEIF(msg_param.data);
5508 return MM_ERROR_NONE;
5511 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5513 GstState element_state = GST_STATE_VOID_PENDING;
5514 GstState element_pending_state = GST_STATE_VOID_PENDING;
5515 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5516 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5518 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5520 MMPLAYER_RECONFIGURE_LOCK(player);
5521 if (!player->gapless.reconfigure) {
5522 MMPLAYER_RECONFIGURE_UNLOCK(player);
5526 LOGI("reconfigure is under process");
5527 MMPLAYER_RECONFIGURE_WAIT(player);
5528 MMPLAYER_RECONFIGURE_UNLOCK(player);
5529 LOGI("reconfigure is completed.");
5531 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5532 &element_state, &element_pending_state, timeout * GST_SECOND);
5533 if (result == GST_STATE_CHANGE_FAILURE)
5534 LOGW("failed to get pipeline state in %d sec", timeout);
5539 /* NOTE : it should be able to call 'stop' anytime*/
5541 _mmplayer_stop(MMHandleType hplayer)
5543 mmplayer_t *player = (mmplayer_t *)hplayer;
5544 int ret = MM_ERROR_NONE;
5548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5550 /* check current state */
5551 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5553 /* need to wait till the rebuilding pipeline is completed */
5554 __mmplayer_check_pipeline_reconfigure_state(player);
5555 MMPLAYER_RECONFIGURE_LOCK(player);
5556 __mmplayer_reset_gapless_state(player);
5557 MMPLAYER_RECONFIGURE_UNLOCK(player);
5559 /* NOTE : application should not wait for EOS after calling STOP */
5560 _mmplayer_cancel_eos_timer(player);
5563 player->seek_state = MMPLAYER_SEEK_NONE;
5566 ret = _mmplayer_gst_stop(player);
5568 if (ret != MM_ERROR_NONE)
5569 LOGE("failed to stop player.");
5577 _mmplayer_pause(MMHandleType hplayer)
5579 mmplayer_t *player = (mmplayer_t *)hplayer;
5580 gint64 pos_nsec = 0;
5581 gboolean async = FALSE;
5582 gint ret = MM_ERROR_NONE;
5586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5588 /* check current state */
5589 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5591 /* check pipeline reconfigure state */
5592 __mmplayer_check_pipeline_reconfigure_state(player);
5594 switch (MMPLAYER_CURRENT_STATE(player)) {
5595 case MM_PLAYER_STATE_READY:
5597 /* check prepare async or not.
5598 * In the case of streaming playback, it's recommended to avoid blocking wait.
5600 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5601 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5603 /* Changing back sync of rtspsrc to async */
5604 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5605 LOGD("async prepare working mode for rtsp");
5611 case MM_PLAYER_STATE_PLAYING:
5613 /* NOTE : store current point to overcome some bad operation
5614 *(returning zero when getting current position in paused state) of some
5617 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5618 LOGW("getting current position failed in paused");
5620 player->last_position = pos_nsec;
5622 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5623 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5624 This causes problem is position calculation during normal pause resume scenarios also.
5625 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5626 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5627 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5628 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5634 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5635 LOGD("doing async pause in case of ms buff src");
5639 /* pause pipeline */
5640 ret = _mmplayer_gst_pause(player, async);
5641 if (ret != MM_ERROR_NONE) {
5642 LOGE("failed to pause player. ret : 0x%x", ret);
5643 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5647 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5648 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5649 LOGE("failed to update display_rotation");
5653 return MM_ERROR_NONE;
5656 /* in case of streaming, pause could take long time.*/
5658 _mmplayer_abort_pause(MMHandleType hplayer)
5660 mmplayer_t *player = (mmplayer_t *)hplayer;
5661 int ret = MM_ERROR_NONE;
5665 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5667 player->pipeline->mainbin,
5668 MM_ERROR_PLAYER_NOT_INITIALIZED);
5670 LOGD("set the pipeline state to READY");
5672 /* set state to READY */
5673 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5674 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5675 if (ret != MM_ERROR_NONE) {
5676 LOGE("fail to change state to READY");
5677 return MM_ERROR_PLAYER_INTERNAL;
5680 LOGD("succeeded in changing state to READY");
5685 _mmplayer_resume(MMHandleType hplayer)
5687 mmplayer_t *player = (mmplayer_t *)hplayer;
5688 int ret = MM_ERROR_NONE;
5689 gboolean async = FALSE;
5693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5695 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5696 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5697 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5701 /* Changing back sync mode rtspsrc to async */
5702 LOGD("async resume for rtsp case");
5706 /* check current state */
5707 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5709 ret = _mmplayer_gst_resume(player, async);
5710 if (ret != MM_ERROR_NONE)
5711 LOGE("failed to resume player.");
5713 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5714 LOGD("force resume even during buffering");
5715 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5724 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5726 mmplayer_t *player = (mmplayer_t *)hplayer;
5727 gint64 pos_nsec = 0;
5728 int ret = MM_ERROR_NONE;
5730 signed long long start = 0, stop = 0;
5731 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5734 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5735 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5737 /* The sound of video is not supported under 0.0 and over 2.0. */
5738 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5739 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5742 _mmplayer_set_mute(hplayer, mute);
5744 if (player->playback_rate == rate)
5745 return MM_ERROR_NONE;
5747 /* If the position is reached at start potion during fast backward, EOS is posted.
5748 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5750 player->playback_rate = rate;
5752 current_state = MMPLAYER_CURRENT_STATE(player);
5754 if (current_state != MM_PLAYER_STATE_PAUSED)
5755 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5757 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5759 if ((current_state == MM_PLAYER_STATE_PAUSED)
5760 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5761 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5762 pos_nsec = player->last_position;
5767 stop = GST_CLOCK_TIME_NONE;
5769 start = GST_CLOCK_TIME_NONE;
5773 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5774 player->playback_rate,
5776 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5777 GST_SEEK_TYPE_SET, start,
5778 GST_SEEK_TYPE_SET, stop)) {
5779 LOGE("failed to set speed playback");
5780 return MM_ERROR_PLAYER_SEEK;
5783 LOGD("succeeded to set speed playback as %0.1f", rate);
5787 return MM_ERROR_NONE;;
5791 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5793 mmplayer_t *player = (mmplayer_t *)hplayer;
5794 int ret = MM_ERROR_NONE;
5798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5800 /* check pipeline reconfigure state */
5801 __mmplayer_check_pipeline_reconfigure_state(player);
5803 ret = _mmplayer_gst_set_position(player, position, FALSE);
5811 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5813 mmplayer_t *player = (mmplayer_t *)hplayer;
5814 int ret = MM_ERROR_NONE;
5816 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5817 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5819 if (g_strrstr(player->type, "video/mpegts"))
5820 __mmplayer_update_duration_value(player);
5822 *duration = player->duration;
5827 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5829 mmplayer_t *player = (mmplayer_t *)hplayer;
5830 int ret = MM_ERROR_NONE;
5832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5834 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5840 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5842 mmplayer_t *player = (mmplayer_t *)hplayer;
5843 int ret = MM_ERROR_NONE;
5847 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5849 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5857 __mmplayer_is_midi_type(gchar *str_caps)
5859 if ((g_strrstr(str_caps, "audio/midi")) ||
5860 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5861 (g_strrstr(str_caps, "application/x-smaf")) ||
5862 (g_strrstr(str_caps, "audio/x-imelody")) ||
5863 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5864 (g_strrstr(str_caps, "audio/xmf")) ||
5865 (g_strrstr(str_caps, "audio/mxmf"))) {
5874 __mmplayer_is_only_mp3_type(gchar *str_caps)
5876 if (g_strrstr(str_caps, "application/x-id3") ||
5877 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5883 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5885 GstStructure *caps_structure = NULL;
5886 gint samplerate = 0;
5890 MMPLAYER_RETURN_IF_FAIL(player && caps);
5892 caps_structure = gst_caps_get_structure(caps, 0);
5894 /* set stream information */
5895 gst_structure_get_int(caps_structure, "rate", &samplerate);
5896 gst_structure_get_int(caps_structure, "channels", &channels);
5898 mm_player_set_attribute((MMHandleType)player, NULL,
5899 "content_audio_samplerate", samplerate,
5900 "content_audio_channels", channels, NULL);
5902 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5906 __mmplayer_update_content_type_info(mmplayer_t *player)
5909 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5911 if (__mmplayer_is_midi_type(player->type)) {
5912 player->bypass_audio_effect = TRUE;
5916 if (!player->streamer) {
5917 LOGD("no need to check streaming type");
5921 if (g_strrstr(player->type, "application/x-hls")) {
5922 /* If it can't know exact type when it parses uri because of redirection case,
5923 * it will be fixed by typefinder or when doing autoplugging.
5925 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5926 player->streamer->is_adaptive_streaming = TRUE;
5927 } else if (g_strrstr(player->type, "application/dash+xml")) {
5928 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5929 player->streamer->is_adaptive_streaming = TRUE;
5932 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5933 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5934 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5936 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5937 if (player->streamer->is_adaptive_streaming)
5938 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5940 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5944 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5949 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5950 GstCaps *caps, gpointer data)
5952 mmplayer_t *player = (mmplayer_t *)data;
5956 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5958 /* store type string */
5959 if (player->type_caps) {
5960 gst_caps_unref(player->type_caps);
5961 player->type_caps = NULL;
5964 player->type_caps = gst_caps_copy(caps);
5965 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5967 MMPLAYER_FREEIF(player->type);
5968 player->type = gst_caps_to_string(caps);
5970 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5971 player, player->type, probability, gst_caps_get_size(caps));
5973 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5974 (g_strrstr(player->type, "audio/x-raw-int"))) {
5975 LOGE("not support media format");
5977 if (player->msg_posted == FALSE) {
5978 MMMessageParamType msg_param;
5979 memset(&msg_param, 0, sizeof(MMMessageParamType));
5981 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5982 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5984 /* don't post more if one was sent already */
5985 player->msg_posted = TRUE;
5990 __mmplayer_update_content_type_info(player);
5992 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5995 pad = gst_element_get_static_pad(tf, "src");
5997 LOGE("fail to get typefind src pad.");
6001 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6002 gboolean async = FALSE;
6003 LOGE("failed to autoplug %s", player->type);
6005 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6007 if (async && player->msg_posted == FALSE)
6008 __mmplayer_handle_missed_plugin(player);
6010 gst_object_unref(GST_OBJECT(pad));
6017 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6019 GstElement *decodebin = NULL;
6023 /* create decodebin */
6024 decodebin = gst_element_factory_make("decodebin", NULL);
6027 LOGE("fail to create decodebin");
6031 /* raw pad handling signal */
6032 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6033 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6035 /* no-more-pad pad handling signal */
6036 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6037 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6039 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6040 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6042 /* This signal is emitted when a pad for which there is no further possible
6043 decoding is added to the decodebin.*/
6044 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6045 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6047 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6048 before looking for any elements that can handle that stream.*/
6049 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6050 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6052 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6053 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6054 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6056 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6057 before looking for any elements that can handle that stream.*/
6058 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6059 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6061 /* This signal is emitted once decodebin has finished decoding all the data.*/
6062 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6063 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6065 /* This signal is emitted when a element is added to the bin.*/
6066 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6067 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6074 __mmplayer_gst_make_queue2(mmplayer_t *player)
6076 GstElement *queue2 = NULL;
6077 gint64 dur_bytes = 0L;
6078 mmplayer_gst_element_t *mainbin = NULL;
6079 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6082 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6084 mainbin = player->pipeline->mainbin;
6086 queue2 = gst_element_factory_make("queue2", "queue2");
6088 LOGE("failed to create buffering queue element");
6092 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6093 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6095 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6097 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6098 * skip the pull mode(file or ring buffering) setting. */
6099 if (dur_bytes > 0) {
6100 if (!g_strrstr(player->type, "video/mpegts")) {
6101 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6102 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6108 _mm_player_streaming_set_queue2(player->streamer,
6112 (guint64)dur_bytes); /* no meaning at the moment */
6118 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6120 mmplayer_gst_element_t *mainbin = NULL;
6121 GstElement *decodebin = NULL;
6122 GstElement *queue2 = NULL;
6123 GstPad *sinkpad = NULL;
6124 GstPad *qsrcpad = NULL;
6127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6129 mainbin = player->pipeline->mainbin;
6131 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6133 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6134 LOGW("need to check: muxed buffer is not null");
6137 queue2 = __mmplayer_gst_make_queue2(player);
6139 LOGE("failed to make queue2");
6143 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6144 LOGE("failed to add buffering queue");
6148 sinkpad = gst_element_get_static_pad(queue2, "sink");
6149 qsrcpad = gst_element_get_static_pad(queue2, "src");
6151 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6152 LOGE("failed to link [%s:%s]-[%s:%s]",
6153 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6157 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6158 LOGE("failed to sync queue2 state with parent");
6162 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6163 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6167 gst_object_unref(GST_OBJECT(sinkpad));
6171 /* create decodebin */
6172 decodebin = _mmplayer_gst_make_decodebin(player);
6174 LOGE("failed to make decodebin");
6178 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6179 LOGE("failed to add decodebin");
6183 /* to force caps on the decodebin element and avoid reparsing stuff by
6184 * typefind. It also avoids a deadlock in the way typefind activates pads in
6185 * the state change */
6186 g_object_set(decodebin, "sink-caps", caps, NULL);
6188 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6190 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6191 LOGE("failed to link [%s:%s]-[%s:%s]",
6192 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6196 gst_object_unref(GST_OBJECT(sinkpad));
6198 gst_object_unref(GST_OBJECT(qsrcpad));
6201 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6202 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6204 /* set decodebin property about buffer in streaming playback. *
6205 * in case of HLS/DASH, it does not need to have big buffer *
6206 * because it is kind of adaptive streaming. */
6207 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6208 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6209 gint high_percent = 0;
6211 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6212 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6214 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6216 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6218 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6219 "high-percent", high_percent,
6220 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6221 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6222 "max-size-buffers", 0, NULL); // disable or automatic
6225 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6226 LOGE("failed to sync decodebin state with parent");
6237 gst_object_unref(GST_OBJECT(sinkpad));
6240 gst_object_unref(GST_OBJECT(qsrcpad));
6243 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6244 * You need to explicitly set elements to the NULL state before
6245 * dropping the final reference, to allow them to clean up.
6247 gst_element_set_state(queue2, GST_STATE_NULL);
6249 /* And, it still has a parent "player".
6250 * You need to let the parent manage the object instead of unreffing the object directly.
6252 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6253 gst_object_unref(queue2);
6258 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6259 * You need to explicitly set elements to the NULL state before
6260 * dropping the final reference, to allow them to clean up.
6262 gst_element_set_state(decodebin, GST_STATE_NULL);
6264 /* And, it still has a parent "player".
6265 * You need to let the parent manage the object instead of unreffing the object directly.
6268 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6269 gst_object_unref(decodebin);
6277 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6282 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6284 LOGD("class : %s, mime : %s", factory_class, mime);
6286 /* add missing plugin */
6287 /* NOTE : msl should check missing plugin for image mime type.
6288 * Some motion jpeg clips can have playable audio track.
6289 * So, msl have to play audio after displaying popup written video format not supported.
6291 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6292 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6293 LOGD("not found demuxer");
6294 player->not_found_demuxer = TRUE;
6295 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6301 if (!g_strrstr(factory_class, "Demuxer")) {
6302 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6303 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6304 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6306 /* check that clip have multi tracks or not */
6307 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6308 LOGD("video plugin is already linked");
6310 LOGW("add VIDEO to missing plugin");
6311 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6312 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6314 } else if (g_str_has_prefix(mime, "audio")) {
6315 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6316 LOGD("audio plugin is already linked");
6318 LOGW("add AUDIO to missing plugin");
6319 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6320 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6328 return MM_ERROR_NONE;
6332 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6334 mmplayer_t *player = (mmplayer_t *)data;
6338 MMPLAYER_RETURN_IF_FAIL(player);
6340 /* remove fakesink. */
6341 if (!_mmplayer_gst_remove_fakesink(player,
6342 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6343 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6344 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6345 * source element are not same. To overcome this situation, this function will called
6346 * several places and several times. Therefore, this is not an error case.
6351 LOGD("[handle: %p] pipeline has completely constructed", player);
6353 if ((player->msg_posted == FALSE) &&
6354 (player->cmd >= MMPLAYER_COMMAND_START))
6355 __mmplayer_handle_missed_plugin(player);
6357 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6361 __mmplayer_check_profile(void)
6364 static int profile_tv = -1;
6366 if (__builtin_expect(profile_tv != -1, 1))
6369 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6370 switch (*profileName) {
6385 __mmplayer_get_next_uri(mmplayer_t *player)
6387 mmplayer_parse_profile_t profile;
6389 guint num_of_list = 0;
6392 num_of_list = g_list_length(player->uri_info.uri_list);
6393 uri_idx = player->uri_info.uri_idx;
6395 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6396 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6397 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6399 LOGW("next uri does not exist");
6403 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6404 LOGE("failed to parse profile");
6408 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6409 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6410 LOGW("uri type is not supported(%d)", profile.uri_type);
6414 LOGD("success to find next uri %d", uri_idx);
6418 if (!uri || uri_idx == num_of_list) {
6419 LOGE("failed to find next uri");
6423 player->uri_info.uri_idx = uri_idx;
6424 if (mm_player_set_attribute((MMHandleType)player, NULL,
6425 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6426 LOGE("failed to set attribute");
6430 SECURE_LOGD("next playback uri: %s", uri);
6435 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6437 #define REPEAT_COUNT_INFINITE -1
6438 #define REPEAT_COUNT_MIN 2
6439 #define ORIGINAL_URI_ONLY 1
6441 MMHandleType attrs = 0;
6445 guint num_of_uri = 0;
6446 int profile_tv = -1;
6450 LOGD("checking for gapless play option");
6452 if (player->build_audio_offload) {
6453 LOGE("offload path is not supportable.");
6457 if (player->pipeline->textbin) {
6458 LOGE("subtitle path is enabled. gapless play is not supported.");
6462 attrs = MMPLAYER_GET_ATTRS(player);
6464 LOGE("fail to get attributes.");
6468 mm_attrs_multiple_get(player->attrs, NULL,
6469 "content_video_found", &video,
6470 "profile_play_count", &count,
6471 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6473 /* gapless playback is not supported in case of video at TV profile. */
6474 profile_tv = __mmplayer_check_profile();
6475 if (profile_tv && video) {
6476 LOGW("not support video gapless playback");
6480 /* check repeat count in case of audio */
6482 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6483 LOGW("gapless is disabled");
6487 num_of_uri = g_list_length(player->uri_info.uri_list);
6489 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6491 if (num_of_uri == ORIGINAL_URI_ONLY) {
6492 /* audio looping path */
6493 if (count >= REPEAT_COUNT_MIN) {
6494 /* decrease play count */
6495 /* we succeeded to rewind. update play count and then wait for next EOS */
6497 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6498 } else if (count != REPEAT_COUNT_INFINITE) {
6499 LOGD("there is no next uri and no repeat");
6502 LOGD("looping cnt %d", count);
6504 /* gapless playback path */
6505 if (!__mmplayer_get_next_uri(player)) {
6506 LOGE("failed to get next uri");
6513 LOGE("unable to play gapless path. EOS will be posted soon");
6518 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6520 GstPad *sinkpad = g_value_get_object (item);
6521 GstElement *element = GST_ELEMENT(user_data);
6522 if (!sinkpad || !element) {
6523 LOGE("invalid parameter");
6527 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6528 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6532 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6534 mmplayer_gst_element_t *sinkbin = NULL;
6535 main_element_id_e concatId = MMPLAYER_M_NUM;
6536 main_element_id_e sinkId = MMPLAYER_M_NUM;
6537 gboolean send_notice = FALSE;
6538 GstElement *element;
6542 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6544 LOGD("type %d", type);
6547 case MM_PLAYER_TRACK_TYPE_AUDIO:
6548 concatId = MMPLAYER_M_A_CONCAT;
6549 sinkId = MMPLAYER_A_BIN;
6550 sinkbin = player->pipeline->audiobin;
6552 case MM_PLAYER_TRACK_TYPE_VIDEO:
6553 concatId = MMPLAYER_M_V_CONCAT;
6554 sinkId = MMPLAYER_V_BIN;
6555 sinkbin = player->pipeline->videobin;
6558 case MM_PLAYER_TRACK_TYPE_TEXT:
6559 concatId = MMPLAYER_M_T_CONCAT;
6560 sinkId = MMPLAYER_T_BIN;
6561 sinkbin = player->pipeline->textbin;
6564 LOGE("requested type is not supportable");
6569 element = player->pipeline->mainbin[concatId].gst;
6573 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6574 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6575 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6576 if (srcpad && sinkpad) {
6577 /* after getting drained signal there is no data flows, so no need to do pad_block */
6578 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6579 gst_pad_unlink(srcpad, sinkpad);
6581 /* send custom event to sink pad to handle it at video sink */
6583 LOGD("send custom event to sinkpad");
6584 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6585 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6586 gst_pad_send_event(sinkpad, event);
6589 gst_object_unref(srcpad);
6590 gst_object_unref(sinkpad);
6593 LOGD("release concat request pad");
6594 /* release and unref requests pad from the selector */
6595 iter = gst_element_iterate_sink_pads(element);
6596 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6597 gst_iterator_resync(iter);
6598 gst_iterator_free(iter);
6604 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6606 mmplayer_track_t *selector = &player->track[type];
6607 mmplayer_gst_element_t *sinkbin = NULL;
6608 main_element_id_e selectorId = MMPLAYER_M_NUM;
6609 main_element_id_e sinkId = MMPLAYER_M_NUM;
6610 GstPad *srcpad = NULL;
6611 GstPad *sinkpad = NULL;
6612 gboolean send_notice = FALSE;
6615 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6617 LOGD("type %d", type);
6620 case MM_PLAYER_TRACK_TYPE_AUDIO:
6621 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6622 sinkId = MMPLAYER_A_BIN;
6623 sinkbin = player->pipeline->audiobin;
6625 case MM_PLAYER_TRACK_TYPE_VIDEO:
6626 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6627 sinkId = MMPLAYER_V_BIN;
6628 sinkbin = player->pipeline->videobin;
6631 case MM_PLAYER_TRACK_TYPE_TEXT:
6632 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6633 sinkId = MMPLAYER_T_BIN;
6634 sinkbin = player->pipeline->textbin;
6637 LOGE("requested type is not supportable");
6642 if (player->pipeline->mainbin[selectorId].gst) {
6645 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6647 if (selector->event_probe_id != 0)
6648 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6649 selector->event_probe_id = 0;
6651 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6652 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6654 if (srcpad && sinkpad) {
6655 /* after getting drained signal there is no data flows, so no need to do pad_block */
6656 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6657 gst_pad_unlink(srcpad, sinkpad);
6659 /* send custom event to sink pad to handle it at video sink */
6661 LOGD("send custom event to sinkpad");
6662 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6663 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6664 gst_pad_send_event(sinkpad, event);
6668 gst_object_unref(sinkpad);
6671 gst_object_unref(srcpad);
6674 LOGD("selector release");
6676 /* release and unref requests pad from the selector */
6677 for (n = 0; n < selector->streams->len; n++) {
6678 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6679 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6682 g_ptr_array_set_size(selector->streams, 0);
6684 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6685 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6687 player->pipeline->mainbin[selectorId].gst = NULL;
6695 __mmplayer_deactivate_old_path(mmplayer_t *player)
6698 MMPLAYER_RETURN_IF_FAIL(player);
6700 if (MMPLAYER_USE_DECODEBIN(player)) {
6701 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6702 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6703 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6704 LOGE("deactivate selector error");
6708 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6709 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6710 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6711 LOGE("deactivate concat error");
6716 _mmplayer_track_destroy(player);
6717 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6719 if (player->streamer) {
6720 _mm_player_streaming_initialize(player->streamer, FALSE);
6721 _mm_player_streaming_destroy(player->streamer);
6722 player->streamer = NULL;
6725 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6731 if (!player->msg_posted) {
6732 MMMessageParamType msg = {0,};
6735 msg.code = MM_ERROR_PLAYER_INTERNAL;
6736 LOGE("gapless_uri_play> deactivate error");
6738 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6739 player->msg_posted = TRUE;
6745 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6747 int result = MM_ERROR_NONE;
6748 mmplayer_t *player = (mmplayer_t *)hplayer;
6751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6752 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6754 if (mm_player_set_attribute(hplayer, NULL,
6755 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6756 LOGE("failed to set attribute");
6757 result = MM_ERROR_PLAYER_INTERNAL;
6759 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6760 LOGE("failed to add the original uri in the uri list.");
6768 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6770 mmplayer_t *player = (mmplayer_t *)hplayer;
6771 guint num_of_list = 0;
6775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6776 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6778 if (player->pipeline && player->pipeline->textbin) {
6779 LOGE("subtitle path is enabled.");
6780 return MM_ERROR_PLAYER_INVALID_STATE;
6783 num_of_list = g_list_length(player->uri_info.uri_list);
6785 if (is_first_path) {
6786 if (num_of_list == 0) {
6787 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6788 SECURE_LOGD("add original path : %s", uri);
6790 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6791 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6793 SECURE_LOGD("change original path : %s", uri);
6796 MMHandleType attrs = 0;
6797 attrs = MMPLAYER_GET_ATTRS(player);
6799 if (num_of_list == 0) {
6800 char *original_uri = NULL;
6803 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6805 if (!original_uri) {
6806 LOGE("there is no original uri.");
6807 return MM_ERROR_PLAYER_INVALID_STATE;
6810 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6811 player->uri_info.uri_idx = 0;
6813 SECURE_LOGD("add original path at first : %s", original_uri);
6817 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6818 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6822 return MM_ERROR_NONE;
6826 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6828 mmplayer_t *player = (mmplayer_t *)hplayer;
6829 char *next_uri = NULL;
6830 guint num_of_list = 0;
6833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6835 num_of_list = g_list_length(player->uri_info.uri_list);
6837 if (num_of_list > 0) {
6838 gint uri_idx = player->uri_info.uri_idx;
6840 if (uri_idx < num_of_list - 1)
6845 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6846 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6848 *uri = g_strdup(next_uri);
6852 return MM_ERROR_NONE;
6856 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6857 GstCaps *caps, gpointer data)
6859 mmplayer_t *player = (mmplayer_t *)data;
6860 const gchar *klass = NULL;
6861 const gchar *mime = NULL;
6862 gchar *caps_str = NULL;
6864 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6865 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6866 caps_str = gst_caps_to_string(caps);
6868 LOGW("unknown type of caps : %s from %s",
6869 caps_str, GST_ELEMENT_NAME(elem));
6871 MMPLAYER_FREEIF(caps_str);
6873 /* There is no available codec. */
6874 __mmplayer_check_not_supported_codec(player, klass, mime);
6878 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6879 GstCaps *caps, gpointer data)
6881 mmplayer_t *player = (mmplayer_t *)data;
6882 const char *mime = NULL;
6883 gboolean ret = TRUE;
6885 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6886 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6888 if (g_str_has_prefix(mime, "audio")) {
6889 GstStructure *caps_structure = NULL;
6890 gint samplerate = 0;
6892 gchar *caps_str = NULL;
6894 caps_structure = gst_caps_get_structure(caps, 0);
6895 gst_structure_get_int(caps_structure, "rate", &samplerate);
6896 gst_structure_get_int(caps_structure, "channels", &channels);
6898 if ((channels > 0 && samplerate == 0)) {
6899 LOGD("exclude audio...");
6903 caps_str = gst_caps_to_string(caps);
6904 /* set it directly because not sent by TAG */
6905 if (g_strrstr(caps_str, "mobile-xmf"))
6906 mm_player_set_attribute((MMHandleType)player, NULL,
6907 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6909 MMPLAYER_FREEIF(caps_str);
6910 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6911 LOGD("already video linked");
6914 LOGD("found new stream");
6921 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6923 gboolean ret = FALSE;
6924 GDBusConnection *conn = NULL;
6926 GVariant *result = NULL;
6927 const gchar *dbus_device_type = NULL;
6928 const gchar *dbus_ret = NULL;
6931 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6933 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6938 result = g_dbus_connection_call_sync(conn,
6939 "org.pulseaudio.Server",
6940 "/org/pulseaudio/StreamManager",
6941 "org.pulseaudio.StreamManager",
6942 "GetCurrentMediaRoutingPath",
6943 g_variant_new("(s)", "out"),
6944 G_VARIANT_TYPE("(ss)"),
6945 G_DBUS_CALL_FLAGS_NONE,
6949 if (!result || err) {
6950 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6955 /* device type is listed in stream-map.json at mmfw-sysconf */
6956 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6958 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6959 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6962 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6963 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6964 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6965 LOGD("audio offload is supportable");
6971 LOGD("audio offload is not supportable");
6974 g_variant_unref(result);
6976 g_object_unref(conn);
6981 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6983 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6984 gint64 position = 0;
6986 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6987 player->pipeline && player->pipeline->mainbin);
6989 MMPLAYER_CMD_LOCK(player);
6990 current_state = MMPLAYER_CURRENT_STATE(player);
6992 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6993 LOGW("getting current position failed in paused");
6995 _mmplayer_unrealize((MMHandleType)player);
6996 _mmplayer_realize((MMHandleType)player);
6998 _mmplayer_set_position((MMHandleType)player, position);
7000 /* async not to be blocked in streaming case */
7001 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7003 _mmplayer_pause((MMHandleType)player);
7005 if (current_state == MM_PLAYER_STATE_PLAYING)
7006 _mmplayer_start((MMHandleType)player);
7007 MMPLAYER_CMD_UNLOCK(player);
7009 LOGD("rebuilding audio pipeline is completed.");
7012 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7014 mmplayer_t *player = (mmplayer_t *)user_data;
7015 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7016 gboolean is_supportable = FALSE;
7018 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7019 LOGW("failed to get device type");
7021 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7023 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7024 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7025 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7026 LOGD("ignore this dev connected info");
7030 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7031 if (player->build_audio_offload == is_supportable) {
7032 LOGD("keep current pipeline without re-building");
7036 /* rebuild pipeline */
7037 LOGD("re-build pipeline - offload: %d", is_supportable);
7038 player->build_audio_offload = FALSE;
7039 __mmplayer_rebuild_audio_pipeline(player);
7045 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7047 unsigned int id = 0;
7049 if (player->audio_device_cb_id != 0) {
7050 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7054 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7055 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7056 LOGD("added device connected cb (%u)", id);
7057 player->audio_device_cb_id = id;
7059 LOGW("failed to add device connected cb");
7066 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7068 mmplayer_t *player = (mmplayer_t *)hplayer;
7071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7072 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7074 *activated = player->build_audio_offload;
7076 LOGD("offload activated : %d", (int)*activated);
7079 return MM_ERROR_NONE;
7083 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7086 this function need to be updated according to the supported media format
7087 @see player->ini.audio_offload_media_format */
7089 if (__mmplayer_is_only_mp3_type(player->type)) {
7090 LOGD("offload supportable media format type");
7098 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7100 gboolean ret = FALSE;
7101 GstElementFactory *factory = NULL;
7104 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7106 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7107 if (!__mmplayer_is_offload_supported_type(player))
7110 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7111 LOGD("there is no audio offload sink");
7115 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7116 LOGW("there is no audio device type to support offload");
7120 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7122 LOGW("there is no installed audio offload sink element");
7125 gst_object_unref(factory);
7127 if (_mmplayer_acquire_hw_resource(player,
7128 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7129 LOGE("failed to acquire audio offload decoder resource");
7133 if (!__mmplayer_add_audio_device_connected_cb(player))
7136 if (!__mmplayer_is_audio_offload_device_type(player))
7139 LOGD("audio offload can be built");
7144 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7150 static GstAutoplugSelectResult
7151 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7153 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7154 int audio_offload = 0;
7156 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7157 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7159 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7160 LOGD("expose audio path to build offload output path");
7161 player->build_audio_offload = TRUE;
7162 /* update codec info */
7163 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7164 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7165 player->audiodec_linked = 1;
7167 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7171 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7172 And need to consider the multi-track audio content.
7173 There is no HW audio decoder in public. */
7175 /* set stream information */
7176 if (!player->audiodec_linked)
7177 _mmplayer_set_audio_attrs(player, caps);
7179 /* update codec info */
7180 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7181 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7182 player->audiodec_linked = 1;
7184 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7186 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7187 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7189 /* mark video decoder for acquire */
7190 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7191 LOGW("video decoder resource is already acquired, skip it.");
7192 ret = GST_AUTOPLUG_SELECT_SKIP;
7196 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7197 LOGE("failed to acquire video decoder resource");
7198 ret = GST_AUTOPLUG_SELECT_SKIP;
7201 player->interrupted_by_resource = FALSE;
7204 /* update codec info */
7205 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7206 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7207 player->videodec_linked = 1;
7215 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7216 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7218 #define DEFAULT_IDX 0xFFFF
7219 #define MIN_FACTORY_NUM 2
7220 mmplayer_t *player = (mmplayer_t *)data;
7221 GValueArray *new_factories = NULL;
7222 GValue val = { 0, };
7223 GstElementFactory *factory = NULL;
7224 const gchar *klass = NULL;
7225 gchar *factory_name = NULL;
7226 guint hw_dec_idx = DEFAULT_IDX;
7227 guint first_sw_dec_idx = DEFAULT_IDX;
7228 guint last_sw_dec_idx = DEFAULT_IDX;
7229 guint new_pos = DEFAULT_IDX;
7230 guint rm_pos = DEFAULT_IDX;
7231 int audio_codec_type;
7232 int video_codec_type;
7233 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7235 if (factories->n_values < MIN_FACTORY_NUM)
7238 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7239 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7242 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7244 for (int i = 0 ; i < factories->n_values ; i++) {
7245 gchar *hw_dec_info = NULL;
7246 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7248 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7250 LOGW("failed to get factory object");
7253 klass = gst_element_factory_get_klass(factory);
7254 factory_name = GST_OBJECT_NAME(factory);
7257 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7259 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7260 if (!player->need_audio_dec_sorting) {
7261 LOGD("sorting is not required");
7264 codec_type = audio_codec_type;
7265 hw_dec_info = player->ini.audiocodec_element_hw;
7266 sw_dec_info = player->ini.audiocodec_element_sw;
7267 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7268 if (!player->need_video_dec_sorting) {
7269 LOGD("sorting is not required");
7272 codec_type = video_codec_type;
7273 hw_dec_info = player->ini.videocodec_element_hw;
7274 sw_dec_info = player->ini.videocodec_element_sw;
7279 if (g_strrstr(factory_name, hw_dec_info)) {
7282 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7283 if (strstr(factory_name, sw_dec_info[j])) {
7284 last_sw_dec_idx = i;
7285 if (first_sw_dec_idx == DEFAULT_IDX) {
7286 first_sw_dec_idx = i;
7291 if (first_sw_dec_idx == DEFAULT_IDX)
7292 LOGW("unknown codec %s", factory_name);
7296 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7299 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7300 if (hw_dec_idx < first_sw_dec_idx)
7302 new_pos = first_sw_dec_idx;
7303 rm_pos = hw_dec_idx + 1;
7304 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7305 if (last_sw_dec_idx < hw_dec_idx)
7307 new_pos = last_sw_dec_idx + 1;
7308 rm_pos = hw_dec_idx;
7313 /* change position - insert H/W decoder according to the new position */
7314 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7316 LOGW("failed to get factory object");
7319 new_factories = g_value_array_copy(factories);
7320 g_value_init (&val, G_TYPE_OBJECT);
7321 g_value_set_object (&val, factory);
7322 g_value_array_insert(new_factories, new_pos, &val);
7323 g_value_unset (&val);
7324 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7326 for (int i = 0 ; i < new_factories->n_values ; i++) {
7327 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7329 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7330 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7332 LOGE("[Re-arranged] failed to get factory object");
7335 return new_factories;
7339 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7340 GstCaps *caps, GstElementFactory *factory, gpointer data)
7342 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7343 mmplayer_t *player = (mmplayer_t *)data;
7345 gchar *factory_name = NULL;
7346 gchar *caps_str = NULL;
7347 const gchar *klass = NULL;
7350 factory_name = GST_OBJECT_NAME(factory);
7351 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7352 caps_str = gst_caps_to_string(caps);
7354 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7356 /* store type string */
7357 if (player->type == NULL) {
7358 player->type = gst_caps_to_string(caps);
7359 __mmplayer_update_content_type_info(player);
7362 /* filtering exclude keyword */
7363 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7364 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7365 LOGW("skipping [%s] by exclude keyword [%s]",
7366 factory_name, player->ini.exclude_element_keyword[idx]);
7368 result = GST_AUTOPLUG_SELECT_SKIP;
7373 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7374 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7375 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7376 factory_name, player->ini.unsupported_codec_keyword[idx]);
7377 result = GST_AUTOPLUG_SELECT_SKIP;
7382 /* exclude webm format */
7383 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7384 * because webm format is not supportable.
7385 * If webm is disabled in "autoplug-continue", there is no state change
7386 * failure or error because the decodebin will expose the pad directly.
7387 * It make MSL invoke _prepare_async_callback.
7388 * So, we need to disable webm format in "autoplug-select" */
7389 if (caps_str && strstr(caps_str, "webm")) {
7390 LOGW("webm is not supported");
7391 result = GST_AUTOPLUG_SELECT_SKIP;
7395 /* check factory class for filtering */
7396 /* NOTE : msl don't need to use image plugins.
7397 * So, those plugins should be skipped for error handling.
7399 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7400 LOGD("skipping [%s] by not required", factory_name);
7401 result = GST_AUTOPLUG_SELECT_SKIP;
7405 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7406 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7407 // TO CHECK : subtitle if needed, add subparse exception.
7408 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7409 result = GST_AUTOPLUG_SELECT_SKIP;
7413 if (g_strrstr(factory_name, "mpegpsdemux")) {
7414 LOGD("skipping PS container - not support");
7415 result = GST_AUTOPLUG_SELECT_SKIP;
7419 if (g_strrstr(factory_name, "mssdemux"))
7420 player->smooth_streaming = TRUE;
7422 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7423 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7426 GstStructure *str = NULL;
7427 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7429 /* don't make video because of not required */
7430 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7431 (!player->set_mode.video_export)) {
7432 LOGD("no need video decoding, expose pad");
7433 result = GST_AUTOPLUG_SELECT_EXPOSE;
7437 /* get w/h for omx state-tune */
7438 /* FIXME: deprecated? */
7439 str = gst_caps_get_structure(caps, 0);
7440 gst_structure_get_int(str, "width", &width);
7443 if (player->v_stream_caps) {
7444 gst_caps_unref(player->v_stream_caps);
7445 player->v_stream_caps = NULL;
7448 player->v_stream_caps = gst_caps_copy(caps);
7449 LOGD("take caps for video state tune");
7450 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7454 if (g_strrstr(klass, "Codec/Decoder")) {
7455 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7456 if (result != GST_AUTOPLUG_SELECT_TRY) {
7457 LOGW("skip add decoder");
7463 MMPLAYER_FREEIF(caps_str);
7469 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7472 //mmplayer_t *player = (mmplayer_t *)data;
7473 GstCaps *caps = NULL;
7475 LOGD("[Decodebin2] pad-removed signal");
7477 caps = gst_pad_query_caps(new_pad, NULL);
7479 LOGW("query caps is NULL");
7483 gchar *caps_str = NULL;
7484 caps_str = gst_caps_to_string(caps);
7486 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7488 MMPLAYER_FREEIF(caps_str);
7489 gst_caps_unref(caps);
7493 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7495 mmplayer_t *player = (mmplayer_t *)data;
7498 MMPLAYER_RETURN_IF_FAIL(player);
7500 LOGD("got about to finish signal");
7502 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7503 LOGW("Fail to get cmd lock");
7507 if (!__mmplayer_verify_gapless_play_path(player)) {
7508 LOGD("decoding is finished.");
7509 MMPLAYER_CMD_UNLOCK(player);
7513 _mmplayer_set_reconfigure_state(player, TRUE);
7514 MMPLAYER_CMD_UNLOCK(player);
7516 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7517 __mmplayer_deactivate_old_path(player);
7523 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7525 mmplayer_t *player = (mmplayer_t *)data;
7526 GstIterator *iter = NULL;
7527 GValue item = { 0, };
7529 gboolean done = FALSE;
7530 gboolean is_all_drained = TRUE;
7533 MMPLAYER_RETURN_IF_FAIL(player);
7535 LOGD("got drained signal");
7537 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7538 LOGW("Fail to get cmd lock");
7542 if (!__mmplayer_verify_gapless_play_path(player)) {
7543 LOGD("decoding is finished.");
7544 MMPLAYER_CMD_UNLOCK(player);
7548 _mmplayer_set_reconfigure_state(player, TRUE);
7549 MMPLAYER_CMD_UNLOCK(player);
7551 /* check decodebin src pads whether they received EOS or not */
7552 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7555 switch (gst_iterator_next(iter, &item)) {
7556 case GST_ITERATOR_OK:
7557 pad = g_value_get_object(&item);
7558 if (pad && !GST_PAD_IS_EOS(pad)) {
7559 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7560 is_all_drained = FALSE;
7563 g_value_reset(&item);
7565 case GST_ITERATOR_RESYNC:
7566 gst_iterator_resync(iter);
7568 case GST_ITERATOR_ERROR:
7569 case GST_ITERATOR_DONE:
7574 g_value_unset(&item);
7575 gst_iterator_free(iter);
7577 if (!is_all_drained) {
7578 LOGD("Wait util the all pads get EOS.");
7583 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7584 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7586 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7587 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7588 __mmplayer_deactivate_old_path(player);
7594 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7596 mmplayer_t *player = (mmplayer_t *)data;
7597 const gchar *klass = NULL;
7598 gchar *factory_name = NULL;
7600 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7601 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7603 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7605 if (__mmplayer_add_dump_buffer_probe(player, element))
7606 LOGD("add buffer probe");
7608 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7609 gchar *selected = NULL;
7610 selected = g_strdup(GST_ELEMENT_NAME(element));
7611 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7613 /* update codec info */
7614 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7615 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7616 player->audiodec_linked = 1;
7617 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7618 /* update codec info */
7619 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7620 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7621 player->videodec_linked = 1;
7624 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7625 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7626 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7628 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7629 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7631 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7632 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7633 "max-video-width", player->adaptive_info.limit.width,
7634 "max-video-height", player->adaptive_info.limit.height, NULL);
7636 } else if (g_strrstr(klass, "Demuxer")) {
7638 LOGD("plugged element is demuxer. take it");
7640 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7641 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7644 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7645 int surface_type = 0;
7647 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7650 // to support trust-zone only
7651 if (g_strrstr(factory_name, "asfdemux")) {
7652 LOGD("set file-location %s", player->profile.uri);
7653 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7654 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7655 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7656 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7657 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7658 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7659 (__mmplayer_is_only_mp3_type(player->type))) {
7660 LOGD("[mpegaudioparse] set streaming pull mode.");
7661 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7663 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7664 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7667 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7668 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7669 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7671 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7672 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7674 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7675 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7676 (MMPLAYER_IS_DASH_STREAMING(player))) {
7677 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7678 _mm_player_streaming_set_multiqueue(player->streamer, element);
7679 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7688 __mmplayer_release_misc(mmplayer_t *player)
7691 bool cur_mode = player->set_mode.rich_audio;
7694 MMPLAYER_RETURN_IF_FAIL(player);
7696 player->sent_bos = FALSE;
7697 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7699 player->seek_state = MMPLAYER_SEEK_NONE;
7701 player->total_bitrate = 0;
7702 player->total_maximum_bitrate = 0;
7704 player->not_found_demuxer = 0;
7706 player->last_position = 0;
7707 player->duration = 0;
7708 player->http_content_size = 0;
7709 player->not_supported_codec = MISSING_PLUGIN_NONE;
7710 player->can_support_codec = FOUND_PLUGIN_NONE;
7711 player->pending_seek.is_pending = false;
7712 player->pending_seek.pos = 0;
7713 player->msg_posted = FALSE;
7714 player->has_many_types = FALSE;
7715 player->is_subtitle_force_drop = FALSE;
7716 player->play_subtitle = FALSE;
7717 player->adjust_subtitle_pos = 0;
7718 player->has_closed_caption = FALSE;
7719 player->set_mode.video_export = false;
7720 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7721 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7723 player->set_mode.rich_audio = cur_mode;
7725 if (player->audio_device_cb_id > 0 &&
7726 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7727 LOGW("failed to remove audio device_connected_callback");
7728 player->audio_device_cb_id = 0;
7730 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7731 player->bitrate[i] = 0;
7732 player->maximum_bitrate[i] = 0;
7735 /* free memory related to audio effect */
7736 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7738 if (player->adaptive_info.var_list) {
7739 g_list_free_full(player->adaptive_info.var_list, g_free);
7740 player->adaptive_info.var_list = NULL;
7743 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7744 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7745 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7747 /* Reset video360 settings to their defaults in case if the pipeline is to be
7750 player->video360_metadata.is_spherical = -1;
7751 player->is_openal_plugin_used = FALSE;
7753 player->is_content_spherical = FALSE;
7754 player->is_video360_enabled = TRUE;
7755 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7756 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7757 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7758 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7759 player->video360_zoom = 1.0f;
7760 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7761 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7763 player->sound.rg_enable = false;
7765 __mmplayer_initialize_video_roi(player);
7770 __mmplayer_release_misc_post(mmplayer_t *player)
7772 char *original_uri = NULL;
7775 /* player->pipeline is already released before. */
7776 MMPLAYER_RETURN_IF_FAIL(player);
7778 player->video_decoded_cb = NULL;
7779 player->video_decoded_cb_user_param = NULL;
7780 player->video_stream_prerolled = false;
7782 player->audio_decoded_cb = NULL;
7783 player->audio_decoded_cb_user_param = NULL;
7784 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7786 player->audio_stream_changed_cb = NULL;
7787 player->audio_stream_changed_cb_user_param = NULL;
7789 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7791 /* clean found audio decoders */
7792 if (player->audio_decoders) {
7793 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7794 player->audio_decoders = NULL;
7797 /* clean the uri list except original uri */
7798 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7800 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7801 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7802 g_list_free_full(tmp, (GDestroyNotify)g_free);
7805 LOGW("failed to get original uri info");
7807 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7808 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7812 /* clear the audio stream buffer list */
7813 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7815 /* clear the video stream bo list */
7816 __mmplayer_video_stream_destroy_bo_list(player);
7817 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7819 if (player->profile.input_mem.buf) {
7820 free(player->profile.input_mem.buf);
7821 player->profile.input_mem.buf = NULL;
7823 player->profile.input_mem.len = 0;
7824 player->profile.input_mem.offset = 0;
7826 player->uri_info.uri_idx = 0;
7831 __mmplayer_check_subtitle(mmplayer_t *player)
7833 MMHandleType attrs = 0;
7834 char *subtitle_uri = NULL;
7838 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7840 /* get subtitle attribute */
7841 attrs = MMPLAYER_GET_ATTRS(player);
7845 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7846 if (!subtitle_uri || !strlen(subtitle_uri))
7849 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7850 player->is_external_subtitle_present = TRUE;
7858 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7860 MMPLAYER_RETURN_IF_FAIL(player);
7862 if (player->eos_timer) {
7863 LOGD("cancel eos timer");
7864 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7865 player->eos_timer = 0;
7872 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7876 MMPLAYER_RETURN_IF_FAIL(player);
7877 MMPLAYER_RETURN_IF_FAIL(sink);
7880 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7882 player->sink_elements = g_list_append(player->sink_elements, sink);
7888 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7892 MMPLAYER_RETURN_IF_FAIL(player);
7893 MMPLAYER_RETURN_IF_FAIL(sink);
7895 player->sink_elements = g_list_remove(player->sink_elements, sink);
7901 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7902 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7904 mmplayer_signal_item_t *item = NULL;
7907 MMPLAYER_RETURN_IF_FAIL(player);
7909 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7910 LOGE("invalid signal type [%d]", type);
7914 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7916 LOGE("cannot connect signal [%s]", signal);
7921 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7922 player->signals[type] = g_list_append(player->signals[type], item);
7928 /* NOTE : be careful with calling this api. please refer to below glib comment
7929 * glib comment : Note that there is a bug in GObject that makes this function much
7930 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7931 * will no longer be called, but, the signal handler is not currently disconnected.
7932 * If the instance is itself being freed at the same time than this doesn't matter,
7933 * since the signal will automatically be removed, but if instance persists,
7934 * then the signal handler will leak. You should not remove the signal yourself
7935 * because in a future versions of GObject, the handler will automatically be
7938 * It's possible to work around this problem in a way that will continue to work
7939 * with future versions of GObject by checking that the signal handler is still
7940 * connected before disconnected it:
7942 * if (g_signal_handler_is_connected(instance, id))
7943 * g_signal_handler_disconnect(instance, id);
7946 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7948 GList *sig_list = NULL;
7949 mmplayer_signal_item_t *item = NULL;
7953 MMPLAYER_RETURN_IF_FAIL(player);
7955 LOGD("release signals type : %d", type);
7957 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7958 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7960 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7961 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7962 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7966 sig_list = player->signals[type];
7968 for (; sig_list; sig_list = sig_list->next) {
7969 item = sig_list->data;
7971 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7972 if (g_signal_handler_is_connected(item->obj, item->sig))
7973 g_signal_handler_disconnect(item->obj, item->sig);
7976 MMPLAYER_FREEIF(item);
7979 g_list_free(player->signals[type]);
7980 player->signals[type] = NULL;
7988 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7990 mmplayer_t *player = 0;
7991 int prev_display_surface_type = 0;
7995 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7997 player = MM_PLAYER_CAST(handle);
7999 /* check video sinkbin is created */
8000 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8001 LOGW("Videosink is already created");
8002 return MM_ERROR_NONE;
8005 LOGD("videosink element is not yet ready");
8007 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8008 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8010 return MM_ERROR_INVALID_ARGUMENT;
8013 /* load previous attributes */
8014 if (player->attrs) {
8015 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8016 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8017 if (prev_display_surface_type == surface_type) {
8018 LOGD("incoming display surface type is same as previous one, do nothing..");
8020 return MM_ERROR_NONE;
8023 LOGE("failed to load attributes");
8025 return MM_ERROR_PLAYER_INTERNAL;
8028 /* videobin is not created yet, so we just set attributes related to display surface */
8029 LOGD("store display attribute for given surface type(%d)", surface_type);
8030 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8031 "display_overlay", wl_surface_id, NULL);
8034 return MM_ERROR_NONE;
8037 /* Note : if silent is true, then subtitle would not be displayed. :*/
8039 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8041 mmplayer_t *player = (mmplayer_t *)hplayer;
8045 /* check player handle */
8046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8048 player->set_mode.subtitle_off = silent;
8050 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8054 return MM_ERROR_NONE;
8058 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8060 mmplayer_gst_element_t *mainbin = NULL;
8061 mmplayer_gst_element_t *textbin = NULL;
8062 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8063 GstState current_state = GST_STATE_VOID_PENDING;
8064 GstState element_state = GST_STATE_VOID_PENDING;
8065 GstState element_pending_state = GST_STATE_VOID_PENDING;
8067 GstEvent *event = NULL;
8068 int result = MM_ERROR_NONE;
8070 GstClock *curr_clock = NULL;
8071 GstClockTime base_time, start_time, curr_time;
8076 /* check player handle */
8077 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8079 player->pipeline->mainbin &&
8080 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8082 mainbin = player->pipeline->mainbin;
8083 textbin = player->pipeline->textbin;
8085 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8087 // sync clock with current pipeline
8088 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8089 curr_time = gst_clock_get_time(curr_clock);
8091 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8092 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8094 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8095 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8097 if (current_state > GST_STATE_READY) {
8098 // sync state with current pipeline
8099 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8100 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8101 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8103 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8104 if (GST_STATE_CHANGE_FAILURE == ret) {
8105 LOGE("fail to state change.");
8106 result = MM_ERROR_PLAYER_INTERNAL;
8110 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8111 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8114 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8115 gst_object_unref(curr_clock);
8118 // seek to current position
8119 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8120 result = MM_ERROR_PLAYER_INVALID_STATE;
8121 LOGE("gst_element_query_position failed, invalid state");
8125 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8126 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);
8128 _mmplayer_gst_send_event_to_sink(player, event);
8130 result = MM_ERROR_PLAYER_INTERNAL;
8131 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8135 /* sync state with current pipeline */
8136 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8137 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8138 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8140 return MM_ERROR_NONE;
8143 /* release text pipeline resource */
8144 player->textsink_linked = 0;
8146 /* release signal */
8147 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8149 /* release textbin with it's children */
8150 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8151 MMPLAYER_FREEIF(player->pipeline->textbin);
8152 player->pipeline->textbin = NULL;
8154 /* release subtitle elem */
8155 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8156 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8162 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8164 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8165 GstState current_state = GST_STATE_VOID_PENDING;
8167 MMHandleType attrs = 0;
8168 mmplayer_gst_element_t *mainbin = NULL;
8169 mmplayer_gst_element_t *textbin = NULL;
8171 gchar *subtitle_uri = NULL;
8172 int result = MM_ERROR_NONE;
8173 const gchar *charset = NULL;
8177 /* check player handle */
8178 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8180 player->pipeline->mainbin &&
8181 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8182 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8184 mainbin = player->pipeline->mainbin;
8185 textbin = player->pipeline->textbin;
8187 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8188 if (current_state < GST_STATE_READY) {
8189 result = MM_ERROR_PLAYER_INVALID_STATE;
8190 LOGE("Pipeline is not in proper state");
8194 attrs = MMPLAYER_GET_ATTRS(player);
8196 LOGE("cannot get content attribute");
8197 result = MM_ERROR_PLAYER_INTERNAL;
8201 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8202 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8203 LOGE("subtitle uri is not proper filepath");
8204 result = MM_ERROR_PLAYER_INVALID_URI;
8208 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8209 LOGE("failed to get storage info of subtitle path");
8210 result = MM_ERROR_PLAYER_INVALID_URI;
8214 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8215 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8217 if (!strcmp(filepath, subtitle_uri)) {
8218 LOGD("subtitle path is not changed");
8221 if (mm_player_set_attribute((MMHandleType)player, NULL,
8222 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8223 LOGE("failed to set attribute");
8228 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8229 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8230 player->subtitle_language_list = NULL;
8231 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8233 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8234 if (ret != GST_STATE_CHANGE_SUCCESS) {
8235 LOGE("failed to change state of textbin to READY");
8236 result = MM_ERROR_PLAYER_INTERNAL;
8240 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8241 if (ret != GST_STATE_CHANGE_SUCCESS) {
8242 LOGE("failed to change state of subparse to READY");
8243 result = MM_ERROR_PLAYER_INTERNAL;
8247 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8248 if (ret != GST_STATE_CHANGE_SUCCESS) {
8249 LOGE("failed to change state of filesrc to READY");
8250 result = MM_ERROR_PLAYER_INTERNAL;
8254 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8256 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8258 charset = _mmplayer_get_charset(filepath);
8260 LOGD("detected charset is %s", charset);
8261 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8264 result = _mmplayer_sync_subtitle_pipeline(player);
8271 /* API to switch between external subtitles */
8273 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8275 int result = MM_ERROR_NONE;
8276 mmplayer_t *player = (mmplayer_t *)hplayer;
8281 /* check player handle */
8282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8284 /* filepath can be null in idle state */
8286 /* check file path */
8287 if ((path = strstr(filepath, "file://")))
8288 result = _mmplayer_exist_file_path(path + 7);
8290 result = _mmplayer_exist_file_path(filepath);
8292 if (result != MM_ERROR_NONE) {
8293 LOGE("invalid subtitle path 0x%X", result);
8294 return result; /* file not found or permission denied */
8298 if (!player->pipeline) {
8300 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8301 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8302 LOGE("failed to set attribute");
8303 return MM_ERROR_PLAYER_INTERNAL;
8306 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8307 /* check filepath */
8308 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8310 if (!__mmplayer_check_subtitle(player)) {
8311 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8312 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8313 LOGE("failed to set attribute");
8314 return MM_ERROR_PLAYER_INTERNAL;
8317 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8318 LOGE("fail to create text pipeline");
8319 return MM_ERROR_PLAYER_INTERNAL;
8322 result = _mmplayer_sync_subtitle_pipeline(player);
8324 result = __mmplayer_change_external_subtitle_language(player, filepath);
8327 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8328 player->is_external_subtitle_added_now = TRUE;
8330 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8331 if (!player->subtitle_language_list) {
8332 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8333 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8334 LOGW("subtitle language list is not updated yet");
8336 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8344 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8346 guint active_idx = 0;
8347 GstStream *stream = NULL;
8348 GList *streams = NULL;
8349 GstEvent *ev = NULL;
8350 GstCaps *caps = NULL;
8352 LOGD("Switching Streams... type: %d, index: %d", type, index);
8354 player->track[type].active_track_index = index;
8356 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8357 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8358 if (player->track[i].total_track_num > 0) {
8359 active_idx = player->track[i].active_track_index;
8360 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8361 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8362 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8364 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8365 caps = gst_stream_get_caps(stream);
8367 _mmplayer_set_audio_attrs(player, caps);
8368 gst_caps_unref(caps);
8374 ev = gst_event_new_select_streams(streams);
8375 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8376 g_list_free(streams);
8378 return MM_ERROR_NONE;
8382 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8384 int result = MM_ERROR_NONE;
8385 gchar *change_pad_name = NULL;
8386 GstPad *sinkpad = NULL;
8387 mmplayer_gst_element_t *mainbin = NULL;
8388 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8389 GstCaps *caps = NULL;
8390 gint total_track_num = 0;
8394 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8395 MM_ERROR_PLAYER_NOT_INITIALIZED);
8397 LOGD("Change Track(%d) to %d", type, index);
8399 mainbin = player->pipeline->mainbin;
8401 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8402 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8403 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8404 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8406 /* Changing Video Track is not supported. */
8407 LOGE("Track Type Error");
8411 if (mainbin[elem_idx].gst == NULL) {
8412 result = MM_ERROR_PLAYER_NO_OP;
8413 LOGD("Req track doesn't exist");
8417 total_track_num = player->track[type].total_track_num;
8418 if (total_track_num <= 0) {
8419 result = MM_ERROR_PLAYER_NO_OP;
8420 LOGD("Language list is not available");
8424 if ((index < 0) || (index >= total_track_num)) {
8425 result = MM_ERROR_INVALID_ARGUMENT;
8426 LOGD("Not a proper index : %d", index);
8430 /*To get the new pad from the selector*/
8431 change_pad_name = g_strdup_printf("sink_%u", index);
8432 if (change_pad_name == NULL) {
8433 result = MM_ERROR_PLAYER_INTERNAL;
8434 LOGD("Pad does not exists");
8438 LOGD("new active pad name: %s", change_pad_name);
8440 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8441 if (sinkpad == NULL) {
8442 LOGD("sinkpad is NULL");
8443 result = MM_ERROR_PLAYER_INTERNAL;
8447 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8448 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8450 caps = gst_pad_get_current_caps(sinkpad);
8451 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8454 gst_object_unref(sinkpad);
8456 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8457 _mmplayer_set_audio_attrs(player, caps);
8460 gst_caps_unref(caps);
8463 MMPLAYER_FREEIF(change_pad_name);
8468 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8470 int result = MM_ERROR_NONE;
8471 mmplayer_t *player = NULL;
8472 mmplayer_gst_element_t *mainbin = NULL;
8474 gint current_active_index = 0;
8476 GstState current_state = GST_STATE_VOID_PENDING;
8481 player = (mmplayer_t *)hplayer;
8482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8484 if (!player->pipeline) {
8485 LOGE("Track %d pre setting -> %d", type, index);
8487 player->track[type].active_track_index = index;
8491 mainbin = player->pipeline->mainbin;
8493 current_active_index = player->track[type].active_track_index;
8495 /*If index is same as running index no need to change the pad*/
8496 if (current_active_index == index)
8499 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8500 result = MM_ERROR_PLAYER_INVALID_STATE;
8504 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8505 if (current_state < GST_STATE_PAUSED) {
8506 result = MM_ERROR_PLAYER_INVALID_STATE;
8507 LOGW("Pipeline not in proper state");
8511 if (MMPLAYER_USE_DECODEBIN(player))
8512 result = __mmplayer_change_selector_pad(player, type, index);
8514 result = __mmplayer_switch_stream(player, type, index);
8516 if (result != MM_ERROR_NONE) {
8517 LOGE("failed to change track");
8521 player->track[type].active_track_index = index;
8523 if (MMPLAYER_USE_DECODEBIN(player)) {
8524 GstEvent *event = NULL;
8525 if (current_state == GST_STATE_PLAYING) {
8526 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8527 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8528 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8530 _mmplayer_gst_send_event_to_sink(player, event);
8532 result = MM_ERROR_PLAYER_INTERNAL;
8543 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8545 mmplayer_t *player = (mmplayer_t *)hplayer;
8549 /* check player handle */
8550 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8552 *silent = player->set_mode.subtitle_off;
8554 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8558 return MM_ERROR_NONE;
8562 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8565 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8567 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8568 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8572 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8573 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8574 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8575 mmplayer_dump_t *dump_s;
8576 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8577 if (dump_s == NULL) {
8578 LOGE("malloc fail");
8582 dump_s->dump_element_file = NULL;
8583 dump_s->dump_pad = NULL;
8584 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8586 if (dump_s->dump_pad) {
8587 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8588 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]);
8589 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8590 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);
8591 /* add list for removed buffer probe and close FILE */
8592 player->dump_list = g_list_append(player->dump_list, dump_s);
8593 LOGD("%s sink pad added buffer probe for dump", factory_name);
8596 MMPLAYER_FREEIF(dump_s);
8597 LOGE("failed to get %s sink pad added", factory_name);
8604 static GstPadProbeReturn
8605 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8607 FILE *dump_data = (FILE *)u_data;
8609 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8610 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8612 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8614 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8616 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8618 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8620 gst_buffer_unmap(buffer, &probe_info);
8622 return GST_PAD_PROBE_OK;
8626 __mmplayer_release_dump_list(GList *dump_list)
8628 GList *d_list = dump_list;
8633 for (; d_list; d_list = g_list_next(d_list)) {
8634 mmplayer_dump_t *dump_s = d_list->data;
8635 if (dump_s->dump_pad) {
8636 if (dump_s->probe_handle_id)
8637 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8638 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8640 if (dump_s->dump_element_file) {
8641 fclose(dump_s->dump_element_file);
8642 dump_s->dump_element_file = NULL;
8644 MMPLAYER_FREEIF(dump_s);
8646 g_list_free(dump_list);
8651 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8653 mmplayer_t *player = (mmplayer_t *)hplayer;
8657 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8660 *exist = (bool)player->has_closed_caption;
8664 return MM_ERROR_NONE;
8668 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8673 LOGD("unref internal gst buffer %p", buffer);
8675 gst_buffer_unref((GstBuffer *)buffer);
8682 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8684 mmplayer_t *player = (mmplayer_t *)hplayer;
8688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8689 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8691 if (MMPLAYER_IS_STREAMING(player))
8692 *timeout = (int)player->ini.live_state_change_timeout;
8694 *timeout = (int)player->ini.localplayback_state_change_timeout;
8696 LOGD("timeout = %d", *timeout);
8699 return MM_ERROR_NONE;
8703 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8707 MMPLAYER_RETURN_IF_FAIL(player);
8709 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8711 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8712 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8713 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8714 player->storage_info[i].id = -1;
8715 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8717 if (path_type != MMPLAYER_PATH_MAX)
8726 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8728 int ret = MM_ERROR_NONE;
8729 mmplayer_t *player = (mmplayer_t *)hplayer;
8730 MMMessageParamType msg_param = {0, };
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8735 LOGW("state changed storage %d:%d", id, state);
8737 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8738 return MM_ERROR_NONE;
8740 /* FIXME: text path should be handled separately. */
8741 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8742 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8743 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8744 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8745 LOGW("external storage is removed");
8747 if (player->msg_posted == FALSE) {
8748 memset(&msg_param, 0, sizeof(MMMessageParamType));
8749 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8750 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8751 player->msg_posted = TRUE;
8754 /* unrealize the player */
8755 ret = _mmplayer_unrealize(hplayer);
8756 if (ret != MM_ERROR_NONE)
8757 LOGE("failed to unrealize");
8765 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8767 int ret = MM_ERROR_NONE;
8768 mmplayer_t *player = (mmplayer_t *)hplayer;
8769 int idx = 0, total = 0;
8770 gchar *result = NULL, *tmp = NULL;
8773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8774 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8776 total = *num = g_list_length(player->adaptive_info.var_list);
8778 LOGW("There is no stream variant info.");
8782 result = g_strdup("");
8783 for (idx = 0 ; idx < total ; idx++) {
8784 stream_variant_t *v_data = NULL;
8785 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8788 gchar data[64] = {0};
8789 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8791 tmp = g_strconcat(result, data, NULL);
8795 LOGW("There is no variant data in %d", idx);
8800 *var_info = (char *)result;
8802 LOGD("variant info %d:%s", *num, *var_info);
8808 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8810 int ret = MM_ERROR_NONE;
8811 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8816 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8818 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8819 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8820 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8822 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8823 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8824 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8825 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8827 /* FIXME: seek to current position for applying new variant limitation */
8836 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8838 int ret = MM_ERROR_NONE;
8839 mmplayer_t *player = (mmplayer_t *)hplayer;
8842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8845 *bandwidth = player->adaptive_info.limit.bandwidth;
8846 *width = player->adaptive_info.limit.width;
8847 *height = player->adaptive_info.limit.height;
8849 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8856 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8858 int ret = MM_ERROR_NONE;
8859 mmplayer_t *player = (mmplayer_t *)hplayer;
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8863 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8864 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8866 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8868 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8869 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8870 else /* live case */
8871 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8873 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8880 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8882 #define IDX_FIRST_SW_CODEC 0
8883 mmplayer_t *player = (mmplayer_t *)hplayer;
8884 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8885 const char *attr_name = NULL;
8886 const char *default_type = NULL;
8887 const char *element_hw = NULL;
8888 const char *element_sw = NULL;
8891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8893 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8895 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8896 switch (stream_type) {
8897 case MM_PLAYER_STREAM_TYPE_AUDIO:
8898 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8899 default_type = player->ini.audiocodec_default_type;
8900 element_hw = player->ini.audiocodec_element_hw;
8901 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8903 case MM_PLAYER_STREAM_TYPE_VIDEO:
8904 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8905 default_type = player->ini.videocodec_default_type;
8906 element_hw = player->ini.videocodec_element_hw;
8907 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8910 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8911 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8915 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8917 if (!strcmp(default_type, "sw"))
8918 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8920 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8922 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8923 codec_type = default_codec_type;
8925 /* to support codec selection, codec info have to be added in ini file.
8926 in case of hw codec is selected, filter elements should be applied
8927 depending on the hw capabilities. */
8928 if (codec_type != default_codec_type) {
8929 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8930 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8931 LOGE("There is no codec for type %d", codec_type);
8932 return MM_ERROR_PLAYER_NO_OP;
8935 LOGD("sorting is required");
8936 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8937 player->need_audio_dec_sorting = TRUE;
8939 player->need_video_dec_sorting = TRUE;
8942 LOGD("update %s codec_type to %d", attr_name, codec_type);
8943 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8946 return MM_ERROR_NONE;
8950 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8952 mmplayer_t *player = (mmplayer_t *)hplayer;
8953 GstElement *rg_vol_element = NULL;
8957 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8959 player->sound.rg_enable = enabled;
8961 /* just hold rgvolume enable value if pipeline is not ready */
8962 if (!player->pipeline || !player->pipeline->audiobin) {
8963 LOGD("pipeline is not ready. holding rgvolume enable value");
8964 return MM_ERROR_NONE;
8967 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8969 if (!rg_vol_element) {
8970 LOGD("rgvolume element is not created");
8971 return MM_ERROR_PLAYER_INTERNAL;
8975 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8977 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8981 return MM_ERROR_NONE;
8985 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8987 mmplayer_t *player = (mmplayer_t *)hplayer;
8988 GstElement *rg_vol_element = NULL;
8989 gboolean enable = FALSE;
8993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8994 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8996 /* just hold enable_rg value if pipeline is not ready */
8997 if (!player->pipeline || !player->pipeline->audiobin) {
8998 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8999 *enabled = player->sound.rg_enable;
9000 return MM_ERROR_NONE;
9003 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9005 if (!rg_vol_element) {
9006 LOGD("rgvolume element is not created");
9007 return MM_ERROR_PLAYER_INTERNAL;
9010 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9011 *enabled = (bool)enable;
9015 return MM_ERROR_NONE;
9019 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9021 mmplayer_t *player = (mmplayer_t *)hplayer;
9022 MMHandleType attrs = 0;
9024 int ret = MM_ERROR_NONE;
9028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030 attrs = MMPLAYER_GET_ATTRS(player);
9031 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9033 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9035 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9036 return MM_ERROR_PLAYER_INTERNAL;
9039 player->video_roi.scale_x = scale_x;
9040 player->video_roi.scale_y = scale_y;
9041 player->video_roi.scale_width = scale_width;
9042 player->video_roi.scale_height = scale_height;
9044 /* check video sinkbin is created */
9045 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9046 return MM_ERROR_NONE;
9048 if (!gst_video_overlay_set_video_roi_area(
9049 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9050 scale_x, scale_y, scale_width, scale_height))
9051 ret = MM_ERROR_PLAYER_INTERNAL;
9053 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9054 scale_x, scale_y, scale_width, scale_height);
9062 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9064 mmplayer_t *player = (mmplayer_t *)hplayer;
9065 int ret = MM_ERROR_NONE;
9069 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9070 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9072 *scale_x = player->video_roi.scale_x;
9073 *scale_y = player->video_roi.scale_y;
9074 *scale_width = player->video_roi.scale_width;
9075 *scale_height = player->video_roi.scale_height;
9077 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9078 *scale_x, *scale_y, *scale_width, *scale_height);
9084 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9086 mmplayer_t *player = (mmplayer_t *)hplayer;
9090 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9092 player->client_pid = pid;
9094 LOGD("client pid[%d] %p", pid, player);
9098 return MM_ERROR_NONE;
9102 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9104 mmplayer_t *player = (mmplayer_t *)hplayer;
9105 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9106 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9111 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9114 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9116 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9118 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9119 return MM_ERROR_NONE;
9121 /* in case of audio codec default type is HW */
9123 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9124 if (player->ini.support_audio_effect)
9125 return MM_ERROR_NONE;
9126 elem_id = MMPLAYER_A_FILTER;
9128 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9129 if (player->ini.support_replaygain_control)
9130 return MM_ERROR_NONE;
9131 elem_id = MMPLAYER_A_RGVOL;
9133 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9134 if (player->ini.support_pitch_control)
9135 return MM_ERROR_NONE;
9136 elem_id = MMPLAYER_A_PITCH;
9138 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9139 if (player->ini.support_audio_effect)
9140 return MM_ERROR_NONE;
9142 /* default case handling is not required */
9145 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9146 LOGW("audio control option [%d] is not available", opt);
9149 /* setting pcm exporting option is allowed before READY state */
9150 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9151 return MM_ERROR_PLAYER_INVALID_STATE;
9153 /* check whether the audio filter exist or not after READY state,
9154 because the sw codec could be added during auto-plugging in some cases */
9155 if (!player->pipeline ||
9156 !player->pipeline->audiobin ||
9157 !player->pipeline->audiobin[elem_id].gst) {
9158 LOGW("there is no audio elem [%d]", elem_id);
9163 LOGD("audio control opt %d, available %d", opt, *available);
9167 return MM_ERROR_NONE;
9171 __mmplayer_update_duration_value(mmplayer_t *player)
9173 gboolean ret = FALSE;
9174 gint64 dur_nsec = 0;
9175 LOGD("try to update duration");
9177 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9178 player->duration = dur_nsec;
9179 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9183 if (player->duration < 0) {
9184 LOGW("duration is Non-Initialized !!!");
9185 player->duration = 0;
9188 /* update streaming service type */
9189 player->streaming_type = _mmplayer_get_stream_service_type(player);
9191 /* check duration is OK */
9192 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9193 /* FIXIT : find another way to get duration here. */
9194 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9200 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9202 /* update audio params
9203 NOTE : We need original audio params and it can be only obtained from src pad of audio
9204 decoder. Below code only valid when we are not using 'resampler' just before
9205 'audioconverter'. */
9206 GstCaps *caps_a = NULL;
9208 gint samplerate = 0, channels = 0;
9209 GstStructure *p = NULL;
9210 GstElement *aconv = NULL;
9212 LOGD("try to update audio attrs");
9214 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9216 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9217 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9218 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9219 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9221 LOGE("there is no audio converter");
9225 pad = gst_element_get_static_pad(aconv, "sink");
9228 LOGW("failed to get pad from audio converter");
9232 caps_a = gst_pad_get_current_caps(pad);
9234 LOGW("not ready to get audio caps");
9235 gst_object_unref(pad);
9239 p = gst_caps_get_structure(caps_a, 0);
9241 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9243 gst_structure_get_int(p, "rate", &samplerate);
9244 gst_structure_get_int(p, "channels", &channels);
9246 mm_player_set_attribute((MMHandleType)player, NULL,
9247 "content_audio_samplerate", samplerate,
9248 "content_audio_channels", channels, NULL);
9250 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9252 gst_caps_unref(caps_a);
9253 gst_object_unref(pad);
9259 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9261 LOGD("try to update video attrs");
9263 GstCaps *caps_v = NULL;
9267 GstStructure *p = NULL;
9269 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9270 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9272 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9274 LOGD("no videosink sink pad");
9278 caps_v = gst_pad_get_current_caps(pad);
9279 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9280 if (!caps_v && player->v_stream_caps) {
9281 caps_v = player->v_stream_caps;
9282 gst_caps_ref(caps_v);
9286 LOGD("no negotiated caps from videosink");
9287 gst_object_unref(pad);
9291 p = gst_caps_get_structure(caps_v, 0);
9292 gst_structure_get_int(p, "width", &width);
9293 gst_structure_get_int(p, "height", &height);
9295 mm_player_set_attribute((MMHandleType)player, NULL,
9296 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9298 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9300 SECURE_LOGD("width : %d height : %d", width, height);
9302 gst_caps_unref(caps_v);
9303 gst_object_unref(pad);
9306 mm_player_set_attribute((MMHandleType)player, NULL,
9307 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9308 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9315 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9317 gboolean ret = FALSE;
9318 guint64 data_size = 0;
9322 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9323 if (!player->duration)
9326 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9327 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9328 if (stat(path, &sb) == 0)
9329 data_size = (guint64)sb.st_size;
9331 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9332 data_size = player->http_content_size;
9335 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9338 guint64 bitrate = 0;
9339 guint64 msec_dur = 0;
9341 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9343 bitrate = data_size * 8 * 1000 / msec_dur;
9344 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9345 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9346 mm_player_set_attribute((MMHandleType)player, NULL,
9347 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9350 LOGD("player duration is less than 0");
9354 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9355 if (player->total_bitrate) {
9356 mm_player_set_attribute((MMHandleType)player, NULL,
9357 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9366 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9368 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9369 data->uri_type = uri_type;
9373 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9375 int ret = MM_ERROR_PLAYER_INVALID_URI;
9377 char *buffer = NULL;
9378 char *seperator = strchr(path, ',');
9379 char ext[100] = {0,}, size[100] = {0,};
9382 if ((buffer = strstr(path, "ext="))) {
9383 buffer += strlen("ext=");
9385 if (strlen(buffer)) {
9386 strncpy(ext, buffer, 99);
9388 if ((seperator = strchr(ext, ','))
9389 || (seperator = strchr(ext, ' '))
9390 || (seperator = strchr(ext, '\0'))) {
9391 seperator[0] = '\0';
9396 if ((buffer = strstr(path, "size="))) {
9397 buffer += strlen("size=");
9399 if (strlen(buffer) > 0) {
9400 strncpy(size, buffer, 99);
9402 if ((seperator = strchr(size, ','))
9403 || (seperator = strchr(size, ' '))
9404 || (seperator = strchr(size, '\0'))) {
9405 seperator[0] = '\0';
9408 mem_size = atoi(size);
9413 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9415 if (mem_size && param) {
9416 if (data->input_mem.buf)
9417 free(data->input_mem.buf);
9418 data->input_mem.buf = malloc(mem_size);
9420 if (data->input_mem.buf) {
9421 memcpy(data->input_mem.buf, param, mem_size);
9422 data->input_mem.len = mem_size;
9423 ret = MM_ERROR_NONE;
9425 LOGE("failed to alloc mem %d", mem_size);
9426 ret = MM_ERROR_PLAYER_INTERNAL;
9429 data->input_mem.offset = 0;
9430 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9437 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9439 gchar *location = NULL;
9442 int ret = MM_ERROR_NONE;
9444 if ((path = strstr(uri, "file://"))) {
9445 location = g_filename_from_uri(uri, NULL, &err);
9446 if (!location || (err != NULL)) {
9447 LOGE("Invalid URI '%s' for filesrc: %s", path,
9448 (err != NULL) ? err->message : "unknown error");
9452 MMPLAYER_FREEIF(location);
9454 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9455 return MM_ERROR_PLAYER_INVALID_URI;
9457 LOGD("path from uri: %s", location);
9460 path = (location != NULL) ? (location) : ((char *)uri);
9463 ret = _mmplayer_exist_file_path(path);
9465 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9466 if (ret == MM_ERROR_NONE) {
9467 if (_mmplayer_is_sdp_file(path)) {
9468 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9469 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9470 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9472 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9473 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9475 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9476 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9478 LOGE("invalid uri, could not play..");
9479 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9482 MMPLAYER_FREEIF(location);
9487 static mmplayer_video_decoded_data_info_t *
9488 __mmplayer_create_stream_from_pad(GstPad *pad)
9490 GstCaps *caps = NULL;
9491 GstStructure *structure = NULL;
9492 unsigned int fourcc = 0;
9493 const gchar *string_format = NULL;
9494 mmplayer_video_decoded_data_info_t *stream = NULL;
9496 MMPixelFormatType format;
9499 caps = gst_pad_get_current_caps(pad);
9501 LOGE("Caps is NULL.");
9506 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9508 structure = gst_caps_get_structure(caps, 0);
9509 gst_structure_get_int(structure, "width", &width);
9510 gst_structure_get_int(structure, "height", &height);
9511 string_format = gst_structure_get_string(structure, "format");
9514 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9515 format = _mmplayer_get_pixtype(fourcc);
9516 gst_video_info_from_caps(&info, caps);
9517 gst_caps_unref(caps);
9520 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9521 LOGE("Wrong condition!!");
9525 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9527 LOGE("failed to alloc mem for video data");
9531 stream->width = width;
9532 stream->height = height;
9533 stream->format = format;
9534 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9540 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9542 unsigned int pitch = 0;
9543 unsigned int size = 0;
9545 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9548 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9549 bo = gst_tizen_memory_get_bos(mem, index);
9551 stream->bo[index] = tbm_bo_ref(bo);
9553 LOGE("failed to get bo for index %d", index);
9556 for (index = 0; index < stream->plane_num; index++) {
9557 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9558 stream->stride[index] = pitch;
9560 stream->elevation[index] = size / pitch;
9562 stream->elevation[index] = stream->height;
9567 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9569 if (stream->format == MM_PIXEL_FORMAT_I420) {
9570 int ret = TBM_SURFACE_ERROR_NONE;
9571 tbm_surface_h surface;
9572 tbm_surface_info_s info;
9574 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9576 ret = tbm_surface_get_info(surface, &info);
9577 if (ret != TBM_SURFACE_ERROR_NONE) {
9578 tbm_surface_destroy(surface);
9582 tbm_surface_destroy(surface);
9583 stream->stride[0] = info.planes[0].stride;
9584 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9585 stream->stride[1] = info.planes[1].stride;
9586 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9587 stream->stride[2] = info.planes[2].stride;
9588 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9589 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9590 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9591 stream->stride[0] = stream->width * 4;
9592 stream->elevation[0] = stream->height;
9593 stream->bo_size = stream->stride[0] * stream->height;
9595 LOGE("Not support format %d", stream->format);
9603 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9605 tbm_bo_handle thandle;
9607 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9608 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9609 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9613 unsigned char *src = NULL;
9614 unsigned char *dest = NULL;
9615 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9617 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9619 LOGE("fail to gst_memory_map");
9623 if (!mapinfo.data) {
9624 LOGE("data pointer is wrong");
9628 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9629 if (!stream->bo[0]) {
9630 LOGE("Fail to tbm_bo_alloc!!");
9634 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9636 LOGE("thandle pointer is wrong");
9640 if (stream->format == MM_PIXEL_FORMAT_I420) {
9641 src_stride[0] = GST_ROUND_UP_4(stream->width);
9642 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9643 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9644 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9647 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9648 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9650 for (i = 0; i < 3; i++) {
9651 src = mapinfo.data + src_offset[i];
9652 dest = thandle.ptr + dest_offset[i];
9657 for (j = 0; j < stream->height >> k; j++) {
9658 memcpy(dest, src, stream->width>>k);
9659 src += src_stride[i];
9660 dest += stream->stride[i];
9663 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9664 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9666 LOGE("Not support format %d", stream->format);
9670 tbm_bo_unmap(stream->bo[0]);
9671 gst_memory_unmap(mem, &mapinfo);
9677 tbm_bo_unmap(stream->bo[0]);
9680 gst_memory_unmap(mem, &mapinfo);
9686 __mmplayer_set_pause_state(mmplayer_t *player)
9688 if (player->sent_bos)
9691 /* rtsp case, get content attrs by GstMessage */
9692 if (MMPLAYER_IS_RTSP_STREAMING(player))
9695 /* it's first time to update all content attrs. */
9696 _mmplayer_update_content_attrs(player, ATTR_ALL);
9700 __mmplayer_set_playing_state(mmplayer_t *player)
9702 gchar *audio_codec = NULL;
9704 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9705 /* initialize because auto resume is done well. */
9706 player->resumed_by_rewind = FALSE;
9707 player->playback_rate = 1.0;
9710 if (player->sent_bos)
9713 /* try to get content metadata */
9715 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9716 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9717 * legacy mmfw-player api
9719 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9721 if ((player->cmd == MMPLAYER_COMMAND_START)
9722 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9723 __mmplayer_handle_missed_plugin(player);
9726 /* check audio codec field is set or not
9727 * we can get it from typefinder or codec's caps.
9729 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9731 /* The codec format can't be sent for audio only case like amr, mid etc.
9732 * Because, parser don't make related TAG.
9733 * So, if it's not set yet, fill it with found data.
9736 if (g_strrstr(player->type, "audio/midi"))
9737 audio_codec = "MIDI";
9738 else if (g_strrstr(player->type, "audio/x-amr"))
9739 audio_codec = "AMR";
9740 else if (g_strrstr(player->type, "audio/mpeg")
9741 && !g_strrstr(player->type, "mpegversion=(int)1"))
9742 audio_codec = "AAC";
9744 audio_codec = "unknown";
9746 if (mm_player_set_attribute((MMHandleType)player, NULL,
9747 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9748 LOGE("failed to set attribute");
9750 LOGD("set audio codec type with caps");