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_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
94 #define PLAYER_DISPLAY_MODE_DST_ROI 5
96 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
98 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
99 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
100 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
101 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
103 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
104 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
106 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
108 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
109 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
110 #define DEFAULT_PCM_OUT_CHANNEL 2
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
146 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
147 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
148 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
149 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
153 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
154 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
155 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
157 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static void __mmplayer_release_misc(mmplayer_t *player);
159 static void __mmplayer_release_misc_post(mmplayer_t *player);
160 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
161 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
164 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
166 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
167 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
168 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
169 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
171 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
172 static gpointer __mmplayer_gapless_play_thread(gpointer data);
173 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
174 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
175 static void __mmplayer_release_dump_list(GList *dump_list);
176 static int __mmplayer_gst_realize(mmplayer_t *player);
177 static int __mmplayer_gst_unrealize(mmplayer_t *player);
178 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
179 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
182 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
183 static void __mmplayer_check_pipeline(mmplayer_t *player);
184 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
185 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
186 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
187 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
188 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
189 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
190 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
191 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
192 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
194 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
196 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
197 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
198 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
200 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
201 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
202 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
203 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
205 static void __mmplayer_set_pause_state(mmplayer_t *player);
206 static void __mmplayer_set_playing_state(mmplayer_t *player);
207 /*===========================================================================================
209 | FUNCTION DEFINITIONS |
211 ========================================================================================== */
215 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
219 count = gst_tag_list_get_tag_size(list, tag);
221 LOGD("count = %d", count);
223 for (i = 0; i < count; i++) {
226 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
227 if (!gst_tag_list_get_string_index(list, tag, i, &str))
228 g_assert_not_reached();
230 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
234 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
236 g_print(" : %s", str);
243 /* This function should be called after the pipeline goes PAUSED or higher
246 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
248 static gboolean has_duration = FALSE;
249 static gboolean has_video_attrs = FALSE;
250 static gboolean has_audio_attrs = FALSE;
251 static gboolean has_bitrate = FALSE;
252 gboolean missing_only = FALSE;
253 gboolean all = FALSE;
254 MMHandleType attrs = 0;
258 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
260 /* check player state here */
261 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
262 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
263 /* give warning now only */
264 LOGW("be careful. content attributes may not available in this state ");
267 /* get content attribute first */
268 attrs = MMPLAYER_GET_ATTRS(player);
270 LOGE("cannot get content attribute");
274 /* get update flag */
276 if (flag & ATTR_MISSING_ONLY) {
278 LOGD("updating missed attr only");
281 if (flag & ATTR_ALL) {
283 has_duration = FALSE;
284 has_video_attrs = FALSE;
285 has_audio_attrs = FALSE;
288 LOGD("updating all attrs");
291 if (missing_only && all) {
292 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
293 missing_only = FALSE;
296 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
297 has_duration = __mmplayer_update_duration_value(player);
299 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
300 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
302 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
303 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
305 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
306 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
309 if (mm_attrs_commit_all(attrs)) {
310 LOGE("failed to update attributes");
320 _mmplayer_get_stream_service_type(mmplayer_t *player)
322 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
326 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
328 player->pipeline->mainbin &&
329 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
330 STREAMING_SERVICE_NONE);
332 /* streaming service type if streaming */
333 if (!MMPLAYER_IS_STREAMING(player))
334 return STREAMING_SERVICE_NONE;
336 streaming_type = (player->duration == 0) ?
337 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
339 switch (streaming_type) {
340 case STREAMING_SERVICE_LIVE:
341 LOGD("it's live streaming");
343 case STREAMING_SERVICE_VOD:
344 LOGD("it's vod streaming");
347 LOGE("should not get here");
353 return streaming_type;
356 /* this function sets the player state and also report
357 * it to applicaton by calling callback function
360 _mmplayer_set_state(mmplayer_t *player, int state)
362 MMMessageParamType msg = {0, };
364 MMPLAYER_RETURN_IF_FAIL(player);
366 if (MMPLAYER_CURRENT_STATE(player) == state) {
367 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
368 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
372 /* update player states */
373 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
374 MMPLAYER_CURRENT_STATE(player) = state;
376 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
377 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
380 MMPLAYER_PRINT_STATE(player);
382 switch (MMPLAYER_CURRENT_STATE(player)) {
383 case MM_PLAYER_STATE_NULL:
384 case MM_PLAYER_STATE_READY:
386 case MM_PLAYER_STATE_PAUSED:
387 __mmplayer_set_pause_state(player);
389 case MM_PLAYER_STATE_PLAYING:
390 __mmplayer_set_playing_state(player);
392 case MM_PLAYER_STATE_NONE:
394 LOGW("invalid target state, there is nothing to do.");
399 /* post message to application */
400 if (MMPLAYER_TARGET_STATE(player) == state) {
401 /* fill the message with state of player */
402 msg.union_type = MM_MSG_UNION_STATE;
403 msg.state.previous = MMPLAYER_PREV_STATE(player);
404 msg.state.current = MMPLAYER_CURRENT_STATE(player);
406 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
408 /* state changed by resource callback */
409 if (player->interrupted_by_resource)
410 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
411 else /* state changed by usecase */
412 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
415 LOGD("intermediate state, do nothing.");
416 MMPLAYER_PRINT_STATE(player);
420 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
421 && !player->sent_bos) {
422 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
423 player->sent_bos = TRUE;
430 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
432 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
433 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
435 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
437 //LOGD("incomming command : %d ", command);
439 current_state = MMPLAYER_CURRENT_STATE(player);
440 pending_state = MMPLAYER_PENDING_STATE(player);
442 MMPLAYER_PRINT_STATE(player);
445 case MMPLAYER_COMMAND_CREATE:
447 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
449 if (current_state == MM_PLAYER_STATE_NULL ||
450 current_state == MM_PLAYER_STATE_READY ||
451 current_state == MM_PLAYER_STATE_PAUSED ||
452 current_state == MM_PLAYER_STATE_PLAYING)
457 case MMPLAYER_COMMAND_DESTROY:
459 /* destroy can called anytime */
461 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
465 case MMPLAYER_COMMAND_REALIZE:
467 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
469 if (pending_state != MM_PLAYER_STATE_NONE) {
472 /* need ready state to realize */
473 if (current_state == MM_PLAYER_STATE_READY)
476 if (current_state != MM_PLAYER_STATE_NULL)
482 case MMPLAYER_COMMAND_UNREALIZE:
484 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
486 if (current_state == MM_PLAYER_STATE_NULL)
491 case MMPLAYER_COMMAND_START:
493 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
495 if (pending_state == MM_PLAYER_STATE_NONE) {
496 if (current_state == MM_PLAYER_STATE_PLAYING)
498 else if (current_state != MM_PLAYER_STATE_READY &&
499 current_state != MM_PLAYER_STATE_PAUSED)
501 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
503 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
504 LOGD("player is going to paused state, just change the pending state as playing");
511 case MMPLAYER_COMMAND_STOP:
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
515 if (current_state == MM_PLAYER_STATE_READY)
518 /* need playing/paused state to stop */
519 if (current_state != MM_PLAYER_STATE_PLAYING &&
520 current_state != MM_PLAYER_STATE_PAUSED)
525 case MMPLAYER_COMMAND_PAUSE:
527 if (MMPLAYER_IS_LIVE_STREAMING(player))
530 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
531 goto NOT_COMPLETED_SEEK;
533 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
535 if (pending_state == MM_PLAYER_STATE_NONE) {
536 if (current_state == MM_PLAYER_STATE_PAUSED)
538 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
540 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
542 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
543 if (current_state == MM_PLAYER_STATE_PAUSED)
544 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
551 case MMPLAYER_COMMAND_RESUME:
553 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
554 goto NOT_COMPLETED_SEEK;
556 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
558 if (pending_state == MM_PLAYER_STATE_NONE) {
559 if (current_state == MM_PLAYER_STATE_PLAYING)
561 else if (current_state != MM_PLAYER_STATE_PAUSED)
563 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
565 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
566 LOGD("player is going to paused state, just change the pending state as playing");
576 player->cmd = command;
578 return MM_ERROR_NONE;
581 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
582 MMPLAYER_STATE_GET_NAME(current_state), command);
583 return MM_ERROR_PLAYER_INVALID_STATE;
586 LOGW("not completed seek");
587 return MM_ERROR_PLAYER_DOING_SEEK;
590 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
591 return MM_ERROR_PLAYER_NO_OP;
594 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
595 return MM_ERROR_PLAYER_NO_OP;
598 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
601 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
604 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
605 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
607 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
608 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
611 LOGE("invalid mmplayer resource type %d", type);
612 return MM_ERROR_PLAYER_INTERNAL;
615 if (player->hw_resource[type] != NULL) {
616 LOGD("[%d type] resource was already acquired", type);
617 return MM_ERROR_NONE;
620 LOGD("mark for acquire [%d type] resource", type);
621 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
622 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
623 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
624 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
625 return MM_ERROR_PLAYER_INTERNAL;
628 rm_ret = mm_resource_manager_commit(player->resource_manager);
629 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
630 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
631 return MM_ERROR_PLAYER_INTERNAL;
635 return MM_ERROR_NONE;
638 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
640 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
644 if (player->hw_resource[type] == NULL) {
645 LOGD("there is no acquired [%d type] resource", type);
646 return MM_ERROR_NONE;
649 LOGD("mark for release [%d type] resource", type);
650 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
651 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
652 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
653 return MM_ERROR_PLAYER_INTERNAL;
656 player->hw_resource[type] = NULL;
658 rm_ret = mm_resource_manager_commit(player->resource_manager);
659 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
660 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
661 return MM_ERROR_PLAYER_INTERNAL;
665 return MM_ERROR_NONE;
669 __mmplayer_initialize_gapless_play(mmplayer_t *player)
675 player->smooth_streaming = FALSE;
676 player->videodec_linked = 0;
677 player->audiodec_linked = 0;
678 player->textsink_linked = 0;
679 player->is_external_subtitle_present = FALSE;
680 player->is_external_subtitle_added_now = FALSE;
681 player->not_supported_codec = MISSING_PLUGIN_NONE;
682 player->can_support_codec = FOUND_PLUGIN_NONE;
683 player->pending_seek.is_pending = false;
684 player->pending_seek.pos = 0;
685 player->msg_posted = FALSE;
686 player->has_many_types = FALSE;
687 player->no_more_pad = FALSE;
688 player->not_found_demuxer = 0;
689 player->seek_state = MMPLAYER_SEEK_NONE;
690 player->is_subtitle_force_drop = FALSE;
691 player->play_subtitle = FALSE;
692 player->adjust_subtitle_pos = 0;
694 player->total_bitrate = 0;
695 player->total_maximum_bitrate = 0;
697 _mmplayer_track_initialize(player);
698 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
700 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
701 player->bitrate[i] = 0;
702 player->maximum_bitrate[i] = 0;
705 if (player->v_stream_caps) {
706 gst_caps_unref(player->v_stream_caps);
707 player->v_stream_caps = NULL;
710 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
712 /* clean found audio decoders */
713 if (player->audio_decoders) {
714 GList *a_dec = player->audio_decoders;
715 for (; a_dec; a_dec = g_list_next(a_dec)) {
716 gchar *name = a_dec->data;
717 MMPLAYER_FREEIF(name);
719 g_list_free(player->audio_decoders);
720 player->audio_decoders = NULL;
723 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
729 __mmplayer_gapless_play_thread(gpointer data)
731 mmplayer_t *player = (mmplayer_t *)data;
732 mmplayer_gst_element_t *mainbin = NULL;
734 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
736 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
737 while (!player->gapless_play_thread_exit) {
738 LOGD("gapless play thread started. waiting for signal.");
739 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
741 LOGD("reconfigure pipeline for gapless play.");
743 if (player->gapless_play_thread_exit) {
744 if (player->gapless.reconfigure) {
745 player->gapless.reconfigure = false;
746 MMPLAYER_PLAYBACK_UNLOCK(player);
748 LOGD("exiting gapless play thread");
752 mainbin = player->pipeline->mainbin;
754 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
758 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
760 /* Initialize Player values */
761 __mmplayer_initialize_gapless_play(player);
763 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
765 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
771 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
773 GSource *source = NULL;
777 source = g_main_context_find_source_by_id(context, source_id);
778 if (source != NULL) {
779 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
780 g_source_destroy(source);
787 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
789 mmplayer_t *player = (mmplayer_t *)hplayer;
790 GstMessage *msg = NULL;
791 GQueue *queue = NULL;
794 MMPLAYER_RETURN_IF_FAIL(player);
796 /* disconnecting bus watch */
797 if (player->bus_watcher)
798 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
799 player->bus_watcher = 0;
801 /* destroy the gst bus msg thread */
802 if (player->bus_msg_thread) {
803 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
804 player->bus_msg_thread_exit = TRUE;
805 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
806 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
808 LOGD("gst bus msg thread exit.");
809 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
810 player->bus_msg_thread = NULL;
812 g_mutex_clear(&player->bus_msg_thread_mutex);
813 g_cond_clear(&player->bus_msg_thread_cond);
816 g_mutex_lock(&player->bus_msg_q_lock);
817 queue = player->bus_msg_q;
818 while (!g_queue_is_empty(queue)) {
819 msg = (GstMessage *)g_queue_pop_head(queue);
824 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
825 gst_message_unref(msg);
827 g_mutex_unlock(&player->bus_msg_q_lock);
833 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
835 GstElement *parent = NULL;
837 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
838 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
841 MMPLAYER_FSINK_LOCK(player);
843 /* get parent of fakesink */
844 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
846 LOGD("fakesink already removed");
850 gst_element_set_locked_state(fakesink->gst, TRUE);
852 /* setting the state to NULL never returns async
853 * so no need to wait for completion of state transiton
855 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
856 LOGE("fakesink state change failure!");
857 /* FIXIT : should I return here? or try to proceed to next? */
860 /* remove fakesink from it's parent */
861 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
862 LOGE("failed to remove fakesink");
864 gst_object_unref(parent);
869 gst_object_unref(parent);
871 LOGD("state-holder removed");
873 gst_element_set_locked_state(fakesink->gst, FALSE);
875 MMPLAYER_FSINK_UNLOCK(player);
880 gst_element_set_locked_state(fakesink->gst, FALSE);
882 MMPLAYER_FSINK_UNLOCK(player);
886 static GstPadProbeReturn
887 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
889 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
890 return GST_PAD_PROBE_OK;
894 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
896 gint64 stop_running_time = 0;
897 gint64 position_running_time = 0;
901 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
902 if ((player->gapless.update_segment[idx] == TRUE) ||
903 !(player->selector[idx].event_probe_id)) {
904 /* LOGW("[%d] skip", idx); */
908 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
910 gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
912 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
914 gst_segment_to_running_time(&player->gapless.segment[idx],
915 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
917 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
919 gst_segment_to_running_time(&player->gapless.segment[idx],
920 GST_FORMAT_TIME, player->duration);
923 position_running_time =
924 gst_segment_to_running_time(&player->gapless.segment[idx],
925 GST_FORMAT_TIME, player->gapless.segment[idx].position);
927 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
928 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
930 GST_TIME_ARGS(stop_running_time),
931 GST_TIME_ARGS(position_running_time),
932 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
933 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
935 position_running_time = MAX(position_running_time, stop_running_time);
936 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
937 GST_FORMAT_TIME, player->gapless.segment[idx].start);
938 position_running_time = MAX(0, position_running_time);
939 position = MAX(position, position_running_time);
943 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
944 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
945 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
947 player->gapless.start_time[stream_type] += position;
953 static GstPadProbeReturn
954 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
956 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
957 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
958 mmplayer_t *player = (mmplayer_t *)data;
959 GstCaps *caps = NULL;
960 GstStructure *str = NULL;
961 const gchar *name = NULL;
962 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
963 gboolean caps_ret = TRUE;
965 if (GST_EVENT_IS_DOWNSTREAM(event) &&
966 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
967 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
968 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
969 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
971 } else if (GST_EVENT_IS_UPSTREAM(event) &&
972 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
976 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
980 if (strstr(name, "audio")) {
981 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
982 } else if (strstr(name, "video")) {
983 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
985 /* text track is not supportable */
986 LOGE("invalid name %s", name);
990 switch (GST_EVENT_TYPE(event)) {
993 /* in case of gapless, drop eos event not to send it to sink */
994 if (player->gapless.reconfigure && !player->msg_posted) {
995 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
996 ret = GST_PAD_PROBE_DROP;
1000 case GST_EVENT_STREAM_START:
1002 __mmplayer_gst_selector_update_start_time(player, stream_type);
1005 case GST_EVENT_FLUSH_STOP:
1007 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1008 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1009 player->gapless.start_time[stream_type] = 0;
1012 case GST_EVENT_SEGMENT:
1017 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1018 gst_event_copy_segment(event, &segment);
1020 if (segment.format != GST_FORMAT_TIME)
1023 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1024 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1025 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1026 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1027 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1028 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1030 /* keep the all the segment ev to cover the seeking */
1031 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1032 player->gapless.update_segment[stream_type] = TRUE;
1034 if (!player->gapless.running)
1037 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1039 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1041 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1042 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1043 gst_event_unref(event);
1044 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1050 gdouble proportion = 0.0;
1051 GstClockTimeDiff diff = 0;
1052 GstClockTime timestamp = 0;
1053 gint64 running_time_diff = -1;
1054 GstQOSType type = 0;
1055 GstEvent *tmpev = NULL;
1057 running_time_diff = player->gapless.segment[stream_type].base;
1059 if (running_time_diff <= 0) /* don't need to adjust */
1062 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1063 gst_event_unref(event);
1065 if (timestamp < running_time_diff) {
1066 LOGW("QOS event from previous group");
1067 ret = GST_PAD_PROBE_DROP;
1071 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1072 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1073 stream_type, GST_TIME_ARGS(timestamp),
1074 GST_TIME_ARGS(running_time_diff),
1075 GST_TIME_ARGS(timestamp - running_time_diff));
1077 timestamp -= running_time_diff;
1079 /* That case is invalid for QoS events */
1080 if (diff < 0 && -diff > timestamp) {
1081 LOGW("QOS event from previous group");
1082 ret = GST_PAD_PROBE_DROP;
1086 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1087 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1097 gst_caps_unref(caps);
1101 /* create fakesink for audio or video path witout audiobin or videobin */
1103 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1105 GstElement *pipeline = NULL;
1106 GstElement *fakesink = NULL;
1107 GstPad *sinkpad = NULL;
1110 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1112 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1115 fakesink = gst_element_factory_make("fakesink", NULL);
1116 if (fakesink == NULL) {
1117 LOGE("failed to create fakesink");
1121 /* store it as it's sink element */
1122 __mmplayer_add_sink(player, fakesink);
1124 gst_bin_add(GST_BIN(pipeline), fakesink);
1127 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1129 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1131 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1132 LOGE("failed to link fakesink");
1133 gst_object_unref(GST_OBJECT(fakesink));
1137 if (strstr(name, "video")) {
1138 if (player->v_stream_caps) {
1139 gst_caps_unref(player->v_stream_caps);
1140 player->v_stream_caps = NULL;
1142 if (player->ini.set_dump_element_flag)
1143 __mmplayer_add_dump_buffer_probe(player, fakesink);
1146 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1147 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1151 gst_object_unref(GST_OBJECT(sinkpad));
1158 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1160 GstElement *pipeline = NULL;
1161 GstElement *selector = NULL;
1162 GstPad *srcpad = NULL;
1165 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1167 selector = gst_element_factory_make("input-selector", NULL);
1169 LOGE("failed to create input-selector");
1172 g_object_set(selector, "sync-streams", TRUE, NULL);
1174 player->pipeline->mainbin[elem_idx].id = elem_idx;
1175 player->pipeline->mainbin[elem_idx].gst = selector;
1177 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1179 srcpad = gst_element_get_static_pad(selector, "src");
1181 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1182 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1183 __mmplayer_gst_selector_blocked, NULL, NULL);
1184 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1185 __mmplayer_gst_selector_event_probe, player, NULL);
1187 gst_element_set_state(selector, GST_STATE_PAUSED);
1189 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1190 gst_bin_add(GST_BIN(pipeline), selector);
1192 gst_object_unref(GST_OBJECT(srcpad));
1199 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1201 mmplayer_t *player = (mmplayer_t *)data;
1202 GstElement *selector = NULL;
1203 GstCaps *caps = NULL;
1204 GstStructure *str = NULL;
1205 const gchar *name = NULL;
1206 GstPad *sinkpad = NULL;
1207 gboolean first_track = FALSE;
1208 gboolean caps_ret = TRUE;
1210 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1211 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1214 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1215 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1217 LOGD("pad-added signal handling");
1219 /* get mimetype from caps */
1220 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1224 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1225 /* LOGD("detected mimetype : %s", name); */
1227 if (strstr(name, "video")) {
1229 gchar *caps_str = NULL;
1231 caps_str = gst_caps_to_string(caps);
1232 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1233 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1234 player->set_mode.video_zc = true;
1236 MMPLAYER_FREEIF(caps_str);
1238 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1239 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1241 LOGD("surface type : %d", stype);
1243 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1244 __mmplayer_gst_create_sinkbin(elem, pad, player);
1248 /* in case of exporting video frame, it requires the 360 video filter.
1249 * it will be handled in _no_more_pads(). */
1250 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1251 __mmplayer_gst_make_fakesink(player, pad, name);
1255 LOGD("video selector is required");
1256 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1257 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1258 } else if (strstr(name, "audio")) {
1259 gint samplerate = 0;
1262 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1263 if (player->build_audio_offload)
1264 player->no_more_pad = TRUE; /* remove state holder */
1265 __mmplayer_gst_create_sinkbin(elem, pad, player);
1269 gst_structure_get_int(str, "rate", &samplerate);
1270 gst_structure_get_int(str, "channels", &channels);
1272 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1273 __mmplayer_gst_make_fakesink(player, pad, name);
1277 LOGD("audio selector is required");
1278 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1279 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1281 } else if (strstr(name, "text")) {
1282 LOGD("text selector is required");
1283 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1284 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1286 LOGE("invalid caps info");
1290 /* check selector and create it */
1291 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1292 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1297 LOGD("input-selector is already created.");
1301 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1303 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1305 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1306 LOGE("failed to link selector");
1307 gst_object_unref(GST_OBJECT(selector));
1312 LOGD("this track will be activated");
1313 g_object_set(selector, "active-pad", sinkpad, NULL);
1316 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1322 gst_caps_unref(caps);
1325 gst_object_unref(GST_OBJECT(sinkpad));
1333 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1335 GstPad *srcpad = NULL;
1338 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1340 LOGD("type %d", type);
1343 LOGD("there is no %d track", type);
1347 srcpad = gst_element_get_static_pad(selector, "src");
1349 LOGE("failed to get srcpad from selector");
1353 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1355 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1357 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1358 if (player->selector[type].block_id) {
1359 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1360 player->selector[type].block_id = 0;
1364 gst_object_unref(GST_OBJECT(srcpad));
1373 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1375 MMHandleType attrs = 0;
1376 gint active_index = 0;
1379 MMPLAYER_RETURN_IF_FAIL(player);
1381 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1383 /* change track to active pad */
1384 active_index = player->selector[type].active_pad_index;
1385 if ((active_index != DEFAULT_TRACK) &&
1386 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1387 LOGW("failed to change %d type track to %d", type, active_index);
1388 player->selector[type].active_pad_index = DEFAULT_TRACK;
1392 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1393 attrs = MMPLAYER_GET_ATTRS(player);
1395 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1396 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1398 if (mm_attrs_commit_all(attrs))
1399 LOGW("failed to commit attrs.");
1401 LOGW("cannot get content attribute");
1410 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1413 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1415 if (!audio_selector) {
1416 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1418 /* in case the source is changed, output can be changed. */
1419 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1420 LOGD("remove previous audiobin if it exist");
1422 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1423 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1425 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1426 MMPLAYER_FREEIF(player->pipeline->audiobin);
1429 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1430 __mmplayer_pipeline_complete(NULL, player);
1435 /* apply the audio track information */
1436 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1438 /* create audio sink path */
1439 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1440 LOGE("failed to create audio sink path");
1449 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1452 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1454 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1455 LOGD("text path is not supproted");
1459 /* apply the text track information */
1460 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1462 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1463 player->has_closed_caption = TRUE;
1465 /* create text decode path */
1466 player->no_more_pad = TRUE;
1468 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1469 LOGE("failed to create text sink path");
1478 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1480 gint64 dur_bytes = 0L;
1483 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1484 player->pipeline->mainbin && player->streamer, FALSE);
1486 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1487 LOGE("fail to get duration.");
1489 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1490 * use file information was already set on Q2 when it was created. */
1491 _mm_player_streaming_set_queue2(player->streamer,
1492 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1493 TRUE, /* use_buffering */
1494 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1495 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1502 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1504 mmplayer_t *player = NULL;
1505 GstElement *video_selector = NULL;
1506 GstElement *audio_selector = NULL;
1507 GstElement *text_selector = NULL;
1510 player = (mmplayer_t *)data;
1512 LOGD("no-more-pad signal handling");
1514 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1515 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1516 LOGW("player is shutting down");
1520 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1521 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1522 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1523 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1524 LOGE("failed to set queue2 buffering");
1529 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1530 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1531 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1533 if (!video_selector && !audio_selector && !text_selector) {
1534 LOGW("there is no selector");
1535 player->no_more_pad = TRUE;
1539 /* create video path followed by video-select */
1540 if (video_selector && !audio_selector && !text_selector)
1541 player->no_more_pad = TRUE;
1543 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1546 /* create audio path followed by audio-select */
1547 if (audio_selector && !text_selector)
1548 player->no_more_pad = TRUE;
1550 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1553 /* create text path followed by text-select */
1554 __mmplayer_create_text_sink_path(player, text_selector);
1557 if (player->gapless.reconfigure) {
1558 player->gapless.reconfigure = FALSE;
1559 MMPLAYER_PLAYBACK_UNLOCK(player);
1566 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1568 gboolean ret = FALSE;
1569 GstElement *pipeline = NULL;
1570 GstPad *sinkpad = NULL;
1573 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1574 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1576 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1578 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1580 LOGE("failed to get pad from sinkbin");
1586 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1587 LOGE("failed to link sinkbin for reusing");
1588 goto EXIT; /* exit either pass or fail */
1592 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1593 LOGE("failed to set state(READY) to sinkbin");
1598 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1599 LOGE("failed to add sinkbin to pipeline");
1604 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1605 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1610 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1611 LOGE("failed to set state(PAUSED) to sinkbin");
1620 gst_object_unref(GST_OBJECT(sinkpad));
1628 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1630 mmplayer_t *player = NULL;
1631 GstCaps *caps = NULL;
1632 gchar *caps_str = NULL;
1633 GstStructure *str = NULL;
1634 const gchar *name = NULL;
1635 GstElement *sinkbin = NULL;
1636 gboolean reusing = FALSE;
1637 gboolean caps_ret = TRUE;
1638 gchar *sink_pad_name = "sink";
1641 player = (mmplayer_t *)data;
1644 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1645 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1647 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1651 caps_str = gst_caps_to_string(caps);
1653 /* LOGD("detected mimetype : %s", name); */
1654 if (strstr(name, "audio")) {
1655 if (player->pipeline->audiobin == NULL) {
1656 const gchar *audio_format = gst_structure_get_string(str, "format");
1658 LOGD("original audio format %s", audio_format);
1659 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1662 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1663 LOGE("failed to create audiobin. continuing without audio");
1667 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1668 LOGD("creating audiobin success");
1671 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1672 LOGD("reusing audiobin");
1673 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1675 } else if (strstr(name, "video")) {
1676 /* 1. zero copy is updated at _decode_pad_added()
1677 * 2. NULL surface type is handled in _decode_pad_added() */
1678 LOGD("zero copy %d", player->set_mode.video_zc);
1679 if (player->pipeline->videobin == NULL) {
1680 int surface_type = 0;
1681 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1682 LOGD("display_surface_type (%d)", surface_type);
1684 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1685 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1686 LOGE("failed to acquire video overlay resource");
1690 player->interrupted_by_resource = FALSE;
1692 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1693 LOGE("failed to create videobin. continuing without video");
1697 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1698 LOGD("creating videosink bin success");
1701 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1702 LOGD("re-using videobin");
1703 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1705 } else if (strstr(name, "text")) {
1706 if (player->pipeline->textbin == NULL) {
1707 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1708 LOGE("failed to create text sink bin. continuing without text");
1712 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1713 player->textsink_linked = 1;
1714 LOGD("creating textsink bin success");
1716 if (!player->textsink_linked) {
1717 LOGD("re-using textbin");
1719 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1720 player->textsink_linked = 1;
1722 /* linked textbin exist which means that the external subtitle path exist already */
1723 LOGW("ignoring internal subtutle since external subtitle is available");
1726 sink_pad_name = "text_sink";
1728 LOGW("unknown mime type %s, ignoring it", name);
1732 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1735 LOGD("[handle: %p] success to create and link sink bin", player);
1737 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1738 * streaming task. if the task blocked, then buffer will not flow to the next element
1739 *(autoplugging element). so this is special hack for streaming. please try to remove it
1741 /* dec stream count. we can remove fakesink if it's zero */
1742 if (player->num_dynamic_pad)
1743 player->num_dynamic_pad--;
1745 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1747 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1748 __mmplayer_pipeline_complete(NULL, player);
1752 MMPLAYER_FREEIF(caps_str);
1755 gst_caps_unref(caps);
1761 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1763 int required_angle = 0; /* Angle required for straight view */
1764 int rotation_angle = 0;
1766 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1767 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1769 /* Counter clockwise */
1770 switch (orientation) {
1775 required_angle = 270;
1778 required_angle = 180;
1781 required_angle = 90;
1785 rotation_angle = display_angle + required_angle;
1786 if (rotation_angle >= 360)
1787 rotation_angle -= 360;
1789 /* chech if supported or not */
1790 if (rotation_angle % 90) {
1791 LOGD("not supported rotation angle = %d", rotation_angle);
1795 switch (rotation_angle) {
1797 *value = MM_DISPLAY_ROTATION_NONE;
1800 *value = MM_DISPLAY_ROTATION_90;
1803 *value = MM_DISPLAY_ROTATION_180;
1806 *value = MM_DISPLAY_ROTATION_270;
1810 LOGD("setting rotation property value : %d", *value);
1816 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1818 /* check video sinkbin is created */
1819 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1821 player->pipeline->videobin &&
1822 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1823 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1824 MM_ERROR_PLAYER_NOT_INITIALIZED);
1826 return MM_ERROR_NONE;
1830 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1832 int display_rotation = 0;
1833 gchar *org_orient = NULL;
1834 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1837 LOGE("cannot get content attribute");
1838 return MM_ERROR_PLAYER_INTERNAL;
1841 if (display_angle) {
1842 /* update user roation */
1843 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1845 /* Counter clockwise */
1846 switch (display_rotation) {
1847 case MM_DISPLAY_ROTATION_NONE:
1850 case MM_DISPLAY_ROTATION_90:
1851 *display_angle = 90;
1853 case MM_DISPLAY_ROTATION_180:
1854 *display_angle = 180;
1856 case MM_DISPLAY_ROTATION_270:
1857 *display_angle = 270;
1860 LOGW("wrong angle type : %d", display_rotation);
1863 LOGD("check user angle: %d", *display_angle);
1867 /* Counter clockwise */
1868 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1871 if (!strcmp(org_orient, "rotate-90"))
1873 else if (!strcmp(org_orient, "rotate-180"))
1875 else if (!strcmp(org_orient, "rotate-270"))
1878 LOGD("original rotation is %s", org_orient);
1880 LOGD("content_video_orientation get fail");
1883 LOGD("check orientation: %d", *orientation);
1886 return MM_ERROR_NONE;
1890 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1892 int rotation_value = 0;
1893 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1894 int display_angle = 0;
1897 /* check video sinkbin is created */
1898 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1901 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1903 /* get rotation value to set */
1904 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1905 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1906 LOGD("set video param : rotate %d", rotation_value);
1910 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1912 MMHandleType attrs = 0;
1916 /* check video sinkbin is created */
1917 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1920 attrs = MMPLAYER_GET_ATTRS(player);
1921 MMPLAYER_RETURN_IF_FAIL(attrs);
1923 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1924 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1925 LOGD("set video param : visible %d", visible);
1929 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1931 MMHandleType attrs = 0;
1932 int display_method = 0;
1935 /* check video sinkbin is created */
1936 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1939 attrs = MMPLAYER_GET_ATTRS(player);
1940 MMPLAYER_RETURN_IF_FAIL(attrs);
1942 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1943 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1944 LOGD("set video param : method %d", display_method);
1948 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1950 MMHandleType attrs = 0;
1951 void *handle = NULL;
1954 /* check video sinkbin is created */
1955 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1956 LOGW("There is no video sink");
1960 attrs = MMPLAYER_GET_ATTRS(player);
1961 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1964 gst_video_overlay_set_video_roi_area(
1965 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1966 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1967 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1968 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1973 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1975 MMHandleType attrs = 0;
1976 void *handle = NULL;
1980 int win_roi_width = 0;
1981 int win_roi_height = 0;
1984 /* check video sinkbin is created */
1985 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1986 LOGW("There is no video sink");
1990 attrs = MMPLAYER_GET_ATTRS(player);
1991 MMPLAYER_RETURN_IF_FAIL(attrs);
1993 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1996 /* It should be set after setting window */
1997 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1998 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1999 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2000 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2002 /* After setting window handle, set display roi area */
2003 gst_video_overlay_set_display_roi_area(
2004 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2005 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2006 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2007 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2012 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2014 MMHandleType attrs = 0;
2015 void *handle = NULL;
2017 /* check video sinkbin is created */
2018 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2021 attrs = MMPLAYER_GET_ATTRS(player);
2022 MMPLAYER_RETURN_IF_FAIL(attrs);
2024 /* common case if using overlay surface */
2025 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2028 /* default is using wl_surface_id */
2029 unsigned int wl_surface_id = 0;
2030 wl_surface_id = *(int *)handle;
2031 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2032 gst_video_overlay_set_wl_window_wl_surface_id(
2033 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2036 /* FIXIT : is it error case? */
2037 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2042 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2044 gboolean update_all_param = FALSE;
2047 /* check video sinkbin is created */
2048 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2049 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2051 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2052 LOGE("can not find tizenwlsink");
2053 return MM_ERROR_PLAYER_INTERNAL;
2056 LOGD("param_name : %s", param_name);
2057 if (!g_strcmp0(param_name, "update_all_param"))
2058 update_all_param = TRUE;
2060 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2061 __mmplayer_video_param_set_display_overlay(player);
2062 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2063 __mmplayer_video_param_set_display_method(player);
2064 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2065 __mmplayer_video_param_set_display_visible(player);
2066 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2067 __mmplayer_video_param_set_display_rotation(player);
2068 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2069 __mmplayer_video_param_set_roi_area(player);
2070 if (update_all_param)
2071 __mmplayer_video_param_set_video_roi_area(player);
2073 return MM_ERROR_NONE;
2077 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2079 MMHandleType attrs = 0;
2080 int surface_type = 0;
2081 int ret = MM_ERROR_NONE;
2085 /* check video sinkbin is created */
2086 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2087 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2089 attrs = MMPLAYER_GET_ATTRS(player);
2091 LOGE("cannot get content attribute");
2092 return MM_ERROR_PLAYER_INTERNAL;
2094 LOGD("param_name : %s", param_name);
2096 /* update display surface */
2097 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2098 LOGD("check display surface type attribute: %d", surface_type);
2100 /* configuring display */
2101 switch (surface_type) {
2102 case MM_DISPLAY_SURFACE_OVERLAY:
2104 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2105 if (ret != MM_ERROR_NONE)
2113 return MM_ERROR_NONE;
2117 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2119 gboolean disable_overlay = FALSE;
2120 mmplayer_t *player = (mmplayer_t *)hplayer;
2123 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2124 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2125 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2126 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2128 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2129 LOGW("Display control is not supported");
2130 return MM_ERROR_PLAYER_INTERNAL;
2133 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2135 if (audio_only == (bool)disable_overlay) {
2136 LOGE("It's the same with current setting: (%d)", audio_only);
2137 return MM_ERROR_NONE;
2141 LOGE("disable overlay");
2142 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2144 /* release overlay resource */
2145 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2146 LOGE("failed to release overlay resource");
2150 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2151 LOGE("failed to acquire video overlay resource");
2154 player->interrupted_by_resource = FALSE;
2156 LOGD("enable overlay");
2157 __mmplayer_video_param_set_display_overlay(player);
2158 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2163 return MM_ERROR_NONE;
2167 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2169 mmplayer_t *player = (mmplayer_t *)hplayer;
2170 gboolean disable_overlay = FALSE;
2174 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2175 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2176 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2177 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2178 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2180 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2181 LOGW("Display control is not supported");
2182 return MM_ERROR_PLAYER_INTERNAL;
2185 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2187 *paudio_only = (bool)disable_overlay;
2189 LOGD("audio_only : %d", *paudio_only);
2193 return MM_ERROR_NONE;
2197 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2199 GList *bucket = element_bucket;
2200 mmplayer_gst_element_t *element = NULL;
2201 mmplayer_gst_element_t *prv_element = NULL;
2202 GstElement *tee_element = NULL;
2203 gint successful_link_count = 0;
2207 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2209 prv_element = (mmplayer_gst_element_t *)bucket->data;
2210 bucket = bucket->next;
2212 for (; bucket; bucket = bucket->next) {
2213 element = (mmplayer_gst_element_t *)bucket->data;
2215 if (element && element->gst) {
2216 if (prv_element && prv_element->gst) {
2217 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2219 prv_element->gst = tee_element;
2221 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2222 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2223 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2227 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2228 LOGD("linking [%s] to [%s] success",
2229 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2230 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2231 successful_link_count++;
2232 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2233 LOGD("keep audio-tee element for next audio pipeline branch");
2234 tee_element = prv_element->gst;
2237 LOGD("linking [%s] to [%s] failed",
2238 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2239 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2245 prv_element = element;
2250 return successful_link_count;
2254 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2256 GList *bucket = element_bucket;
2257 mmplayer_gst_element_t *element = NULL;
2258 int successful_add_count = 0;
2262 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2263 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2265 for (; bucket; bucket = bucket->next) {
2266 element = (mmplayer_gst_element_t *)bucket->data;
2268 if (element && element->gst) {
2269 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2270 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2271 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2272 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2275 successful_add_count++;
2281 return successful_add_count;
2285 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2287 mmplayer_t *player = (mmplayer_t *)data;
2288 GstCaps *caps = NULL;
2289 GstStructure *str = NULL;
2291 gboolean caps_ret = TRUE;
2295 MMPLAYER_RETURN_IF_FAIL(pad);
2296 MMPLAYER_RETURN_IF_FAIL(unused);
2297 MMPLAYER_RETURN_IF_FAIL(data);
2299 caps = gst_pad_get_current_caps(pad);
2303 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2307 LOGD("name = %s", name);
2309 if (strstr(name, "audio")) {
2310 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2312 if (player->audio_stream_changed_cb) {
2313 LOGE("call the audio stream changed cb");
2314 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2316 } else if (strstr(name, "video")) {
2317 if ((name = gst_structure_get_string(str, "format")))
2318 player->set_mode.video_zc = name[0] == 'S';
2320 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2322 if (player->video_stream_changed_cb) {
2323 LOGE("call the video stream changed cb");
2324 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2327 LOGW("invalid caps info");
2332 gst_caps_unref(caps);
2340 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2345 MMPLAYER_RETURN_IF_FAIL(player);
2347 if (player->audio_stream_buff_list) {
2348 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2349 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2352 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2353 __mmplayer_audio_stream_send_data(player, tmp);
2355 MMPLAYER_FREEIF(tmp->pcm_data);
2356 MMPLAYER_FREEIF(tmp);
2359 g_list_free(player->audio_stream_buff_list);
2360 player->audio_stream_buff_list = NULL;
2367 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2369 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2372 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2374 audio_stream.bitrate = a_buffer->bitrate;
2375 audio_stream.channel = a_buffer->channel;
2376 audio_stream.depth = a_buffer->depth;
2377 audio_stream.is_little_endian = a_buffer->is_little_endian;
2378 audio_stream.channel_mask = a_buffer->channel_mask;
2379 audio_stream.data_size = a_buffer->data_size;
2380 audio_stream.data = a_buffer->pcm_data;
2381 audio_stream.pcm_format = a_buffer->pcm_format;
2383 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2384 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2390 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2392 mmplayer_t *player = (mmplayer_t *)data;
2393 const gchar *pcm_format = NULL;
2397 gint endianness = 0;
2398 guint64 channel_mask = 0;
2399 void *a_data = NULL;
2401 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2402 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2406 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2408 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2409 a_data = mapinfo.data;
2410 a_size = mapinfo.size;
2412 GstCaps *caps = gst_pad_get_current_caps(pad);
2413 GstStructure *structure = gst_caps_get_structure(caps, 0);
2415 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2416 pcm_format = gst_structure_get_string(structure, "format");
2417 gst_structure_get_int(structure, "rate", &rate);
2418 gst_structure_get_int(structure, "channels", &channel);
2419 gst_structure_get_int(structure, "depth", &depth);
2420 gst_structure_get_int(structure, "endianness", &endianness);
2421 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2422 gst_caps_unref(GST_CAPS(caps));
2424 /* In case of the sync is false, use buffer list. *
2425 * The num of buffer list depends on the num of audio channels */
2426 if (player->audio_stream_buff_list) {
2427 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2428 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2430 if (channel_mask == tmp->channel_mask) {
2431 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2432 if (tmp->data_size + a_size < tmp->buff_size) {
2433 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2434 tmp->data_size += a_size;
2436 /* send data to client */
2437 __mmplayer_audio_stream_send_data(player, tmp);
2439 if (a_size > tmp->buff_size) {
2440 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2441 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2442 if (tmp->pcm_data == NULL) {
2443 LOGE("failed to realloc data.");
2446 tmp->buff_size = a_size;
2448 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2449 memcpy(tmp->pcm_data, a_data, a_size);
2450 tmp->data_size = a_size;
2455 LOGE("data is empty in list.");
2461 /* create new audio stream data for newly found audio channel */
2462 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2463 if (a_buffer == NULL) {
2464 LOGE("failed to alloc data.");
2467 a_buffer->bitrate = rate;
2468 a_buffer->channel = channel;
2469 a_buffer->depth = depth;
2470 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2471 a_buffer->channel_mask = channel_mask;
2472 a_buffer->data_size = a_size;
2473 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2475 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2476 /* If sync is FALSE, use buffer list to reduce the IPC. */
2477 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2478 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2479 if (a_buffer->pcm_data == NULL) {
2480 LOGE("failed to alloc data.");
2481 MMPLAYER_FREEIF(a_buffer);
2484 memcpy(a_buffer->pcm_data, a_data, a_size);
2485 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2486 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2488 /* If sync is TRUE, send data directly. */
2489 a_buffer->pcm_data = a_data;
2490 __mmplayer_audio_stream_send_data(player, a_buffer);
2491 MMPLAYER_FREEIF(a_buffer);
2495 gst_buffer_unmap(buffer, &mapinfo);
2500 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2502 mmplayer_t *player = (mmplayer_t *)data;
2503 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2504 GstPad *sinkpad = NULL;
2505 GstElement *queue = NULL, *sink = NULL;
2508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2510 queue = gst_element_factory_make("queue", NULL);
2511 if (queue == NULL) {
2512 LOGD("fail make queue");
2516 sink = gst_element_factory_make("fakesink", NULL);
2518 LOGD("fail make fakesink");
2522 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2524 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2525 LOGW("failed to link queue & sink");
2529 sinkpad = gst_element_get_static_pad(queue, "sink");
2531 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2532 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2536 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2538 gst_object_unref(sinkpad);
2539 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2540 g_object_set(sink, "sync", TRUE, NULL);
2541 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2543 /* keep the first sink reference only */
2544 if (!audiobin[MMPLAYER_A_SINK].gst) {
2545 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2546 audiobin[MMPLAYER_A_SINK].gst = sink;
2549 gst_element_set_state(sink, GST_STATE_PAUSED);
2550 gst_element_set_state(queue, GST_STATE_PAUSED);
2552 _mmplayer_add_signal_connection(player,
2554 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2556 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2559 __mmplayer_add_sink(player, sink);
2565 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2567 gst_object_unref(GST_OBJECT(queue));
2571 gst_object_unref(GST_OBJECT(sink));
2575 gst_object_unref(GST_OBJECT(sinkpad));
2583 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2585 #define MAX_PROPS_LEN 128
2586 gint latency_mode = 0;
2587 gchar *stream_type = NULL;
2588 gchar *latency = NULL;
2590 gchar stream_props[MAX_PROPS_LEN] = {0,};
2591 GstStructure *props = NULL;
2594 * It should be set after player creation through attribute.
2595 * But, it can not be changed during playing.
2598 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2600 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2601 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2604 LOGE("stream_type is null.");
2606 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2607 stream_type, stream_id);
2608 props = gst_structure_from_string(stream_props, NULL);
2609 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2610 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2611 gst_structure_free(props);
2614 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2616 switch (latency_mode) {
2617 case AUDIO_LATENCY_MODE_LOW:
2618 latency = g_strndup("low", 3);
2620 case AUDIO_LATENCY_MODE_MID:
2621 latency = g_strndup("mid", 3);
2623 case AUDIO_LATENCY_MODE_HIGH:
2624 latency = g_strndup("high", 4);
2628 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2632 LOGD("audiosink property - latency=%s", latency);
2634 MMPLAYER_FREEIF(latency);
2640 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2642 mmplayer_gst_element_t *audiobin = NULL;
2645 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2647 audiobin = player->pipeline->audiobin;
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2650 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2653 if (player->video360_yaw_radians <= M_PI &&
2654 player->video360_yaw_radians >= -M_PI &&
2655 player->video360_pitch_radians <= M_PI_2 &&
2656 player->video360_pitch_radians >= -M_PI_2) {
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2658 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2659 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2660 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2662 "source-orientation-y", player->video360_metadata.init_view_heading,
2663 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2670 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2672 mmplayer_gst_element_t *audiobin = NULL;
2673 GstPad *sink_pad = NULL;
2674 GstCaps *acaps = NULL;
2676 int pitch_control = 0;
2677 double pitch_value = 1.0;
2680 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2681 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2683 audiobin = player->pipeline->audiobin;
2685 LOGD("make element for normal audio playback");
2687 /* audio bin structure for playback. {} means optional.
2688 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2690 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2691 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2694 /* for pitch control */
2695 mm_attrs_multiple_get(player->attrs, NULL,
2696 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2697 MM_PLAYER_PITCH_VALUE, &pitch_value,
2700 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2701 if (pitch_control && (player->videodec_linked == 0)) {
2702 GstElementFactory *factory;
2704 factory = gst_element_factory_find("pitch");
2706 gst_object_unref(factory);
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2712 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2715 LOGW("there is no pitch element");
2720 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2722 /* replaygain volume */
2723 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2724 if (player->sound.rg_enable)
2725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2732 /* for logical volume control */
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2736 if (player->sound.mute) {
2737 LOGD("mute enabled");
2738 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2741 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2743 /* audio effect element. if audio effect is enabled */
2744 if ((strcmp(player->ini.audioeffect_element, ""))
2746 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2747 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2749 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2751 if ((!player->bypass_audio_effect)
2752 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2753 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2754 if (!_mmplayer_audio_effect_custom_apply(player))
2755 LOGI("apply audio effect(custom) setting success");
2759 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2760 && (player->set_mode.rich_audio)) {
2761 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2765 /* create audio sink */
2766 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2767 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2768 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2770 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2771 if (player->is_360_feature_enabled &&
2772 player->is_content_spherical &&
2774 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2775 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2776 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2778 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2780 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2783 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2785 gst_caps_unref(acaps);
2787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2789 player->is_openal_plugin_used = TRUE;
2791 if (player->is_360_feature_enabled && player->is_content_spherical)
2792 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2793 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2796 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2797 (player->videodec_linked && player->ini.use_system_clock)) {
2798 LOGD("system clock will be used.");
2799 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2802 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2803 __mmplayer_gst_set_pulsesink_property(player);
2804 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2805 __mmplayer_gst_set_openalsink_property(player);
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2809 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2811 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2812 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2813 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2814 gst_object_unref(GST_OBJECT(sink_pad));
2816 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2819 return MM_ERROR_NONE;
2821 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2823 return MM_ERROR_PLAYER_INTERNAL;
2827 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2829 mmplayer_gst_element_t *audiobin = NULL;
2830 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2832 gchar *dst_format = NULL;
2834 int dst_samplerate = 0;
2835 int dst_channels = 0;
2836 GstCaps *caps = NULL;
2837 char *caps_str = NULL;
2840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2841 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2843 audiobin = player->pipeline->audiobin;
2845 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2847 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2849 [case 1] extract interleave audio pcm without playback
2850 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2851 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2853 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2855 [case 2] deinterleave for each channel without playback
2856 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2857 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2859 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2860 - fakesink (sync or not)
2863 [case 3] [case 1(sync only)] + playback
2864 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2866 * src - ... - tee - queue1 - playback path
2867 - queue2 - [case1 pipeline with sync]
2869 [case 4] [case 2(sync only)] + playback
2870 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2872 * src - ... - tee - queue1 - playback path
2873 - queue2 - [case2 pipeline with sync]
2877 /* 1. create tee and playback path
2878 'tee' should be added at first to copy the decoded stream
2880 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2882 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2884 /* tee - path 1 : for playback path */
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2886 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2888 /* tee - path 2 : for extract path */
2889 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2890 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2893 /* if there is tee, 'tee - path 2' is linked here */
2895 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2898 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2900 /* 2. decide the extract pcm format */
2901 mm_attrs_multiple_get(player->attrs, NULL,
2902 "pcm_audioformat", &dst_format, &dst_len,
2903 "pcm_extraction_samplerate", &dst_samplerate,
2904 "pcm_extraction_channels", &dst_channels,
2907 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2908 dst_format, dst_len, dst_samplerate, dst_channels);
2910 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2911 mm_attrs_multiple_get(player->attrs, NULL,
2912 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2913 "content_audio_samplerate", &dst_samplerate,
2914 "content_audio_channels", &dst_channels,
2917 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2918 dst_format, dst_len, dst_samplerate, dst_channels);
2920 /* If there is no enough information, set it to platform default value. */
2921 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2922 LOGD("set platform default format");
2923 dst_format = DEFAULT_PCM_OUT_FORMAT;
2925 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2926 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2929 /* 3. create capsfilter */
2930 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2931 caps = gst_caps_new_simple("audio/x-raw",
2932 "format", G_TYPE_STRING, dst_format,
2933 "rate", G_TYPE_INT, dst_samplerate,
2934 "channels", G_TYPE_INT, dst_channels,
2937 caps_str = gst_caps_to_string(caps);
2938 LOGD("new caps : %s", caps_str);
2940 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2943 gst_caps_unref(caps);
2944 MMPLAYER_FREEIF(caps_str);
2946 /* 4-1. create deinterleave to extract pcm for each channel */
2947 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2948 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2949 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2951 /* audiosink will be added after getting signal for each channel */
2952 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2953 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2955 /* 4-2. create fakesink to extract interlevaed pcm */
2956 LOGD("add audio fakesink for interleaved audio");
2957 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2958 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2959 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2960 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2962 _mmplayer_add_signal_connection(player,
2963 G_OBJECT(audiobin[extract_sink_id].gst),
2964 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2966 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2969 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2973 return MM_ERROR_NONE;
2975 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2977 return MM_ERROR_PLAYER_INTERNAL;
2981 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2983 int ret = MM_ERROR_NONE;
2984 mmplayer_gst_element_t *audiobin = NULL;
2985 GList *element_bucket = NULL;
2988 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2989 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2991 audiobin = player->pipeline->audiobin;
2993 if (player->build_audio_offload) { /* skip all the audio filters */
2994 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2996 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2997 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2998 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3000 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3004 /* FIXME: need to mention the supportable condition at API reference */
3005 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3006 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3008 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3010 if (ret != MM_ERROR_NONE)
3013 LOGD("success to make audio bin element");
3014 *bucket = element_bucket;
3017 return MM_ERROR_NONE;
3020 LOGE("failed to make audio bin element");
3021 g_list_free(element_bucket);
3025 return MM_ERROR_PLAYER_INTERNAL;
3029 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3031 mmplayer_gst_element_t *first_element = NULL;
3032 mmplayer_gst_element_t *audiobin = NULL;
3034 GstPad *ghostpad = NULL;
3035 GList *element_bucket = NULL;
3039 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3042 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3044 LOGE("failed to allocate memory for audiobin");
3045 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3049 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3050 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3051 if (!audiobin[MMPLAYER_A_BIN].gst) {
3052 LOGE("failed to create audiobin");
3057 player->pipeline->audiobin = audiobin;
3059 /* create audio filters and audiosink */
3060 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3063 /* adding created elements to bin */
3064 LOGD("adding created elements to bin");
3065 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3068 /* linking elements in the bucket by added order. */
3069 LOGD("Linking elements in the bucket by added order.");
3070 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3073 /* get first element's sinkpad for creating ghostpad */
3074 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3075 if (!first_element) {
3076 LOGE("failed to get first elem");
3080 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3082 LOGE("failed to get pad from first element of audiobin");
3086 ghostpad = gst_ghost_pad_new("sink", pad);
3088 LOGE("failed to create ghostpad");
3092 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3093 LOGE("failed to add ghostpad to audiobin");
3097 gst_object_unref(pad);
3099 g_list_free(element_bucket);
3102 return MM_ERROR_NONE;
3105 LOGD("ERROR : releasing audiobin");
3108 gst_object_unref(GST_OBJECT(pad));
3111 gst_object_unref(GST_OBJECT(ghostpad));
3114 g_list_free(element_bucket);
3116 /* release element which are not added to bin */
3117 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3118 /* NOTE : skip bin */
3119 if (audiobin[i].gst) {
3120 GstObject *parent = NULL;
3121 parent = gst_element_get_parent(audiobin[i].gst);
3124 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3125 audiobin[i].gst = NULL;
3127 gst_object_unref(GST_OBJECT(parent));
3131 /* release audiobin with it's childs */
3132 if (audiobin[MMPLAYER_A_BIN].gst)
3133 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3135 MMPLAYER_FREEIF(audiobin);
3137 player->pipeline->audiobin = NULL;
3139 return MM_ERROR_PLAYER_INTERNAL;
3143 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3145 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3149 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3151 int ret = MM_ERROR_NONE;
3153 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3154 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3156 MMPLAYER_VIDEO_BO_LOCK(player);
3158 if (player->video_bo_list) {
3159 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3160 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3161 if (tmp && tmp->bo == bo) {
3163 LOGD("release bo %p", bo);
3164 tbm_bo_unref(tmp->bo);
3165 MMPLAYER_VIDEO_BO_UNLOCK(player);
3166 MMPLAYER_VIDEO_BO_SIGNAL(player);
3171 /* hw codec is running or the list was reset for DRC. */
3172 LOGW("there is no bo list.");
3174 MMPLAYER_VIDEO_BO_UNLOCK(player);
3176 LOGW("failed to find bo %p", bo);
3181 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3186 MMPLAYER_RETURN_IF_FAIL(player);
3188 MMPLAYER_VIDEO_BO_LOCK(player);
3189 if (player->video_bo_list) {
3190 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3191 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3192 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3195 tbm_bo_unref(tmp->bo);
3199 g_list_free(player->video_bo_list);
3200 player->video_bo_list = NULL;
3202 player->video_bo_size = 0;
3203 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3213 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3214 gboolean ret = TRUE;
3216 /* check DRC, if it is, destroy the prev bo list to create again */
3217 if (player->video_bo_size != size) {
3218 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3219 __mmplayer_video_stream_destroy_bo_list(player);
3220 player->video_bo_size = size;
3223 MMPLAYER_VIDEO_BO_LOCK(player);
3225 if ((!player->video_bo_list) ||
3226 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3228 /* create bo list */
3230 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3232 if (player->video_bo_list) {
3233 /* if bo list did not created all, try it again. */
3234 idx = g_list_length(player->video_bo_list);
3235 LOGD("bo list exist(len: %d)", idx);
3238 for (; idx < player->ini.num_of_video_bo; idx++) {
3239 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3241 LOGE("Fail to alloc bo_info.");
3244 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3246 LOGE("Fail to tbm_bo_alloc.");
3247 MMPLAYER_FREEIF(bo_info);
3250 bo_info->used = FALSE;
3251 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3254 /* update video num buffers */
3255 player->video_num_buffers = idx;
3256 if (idx == player->ini.num_of_video_bo)
3257 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3260 MMPLAYER_VIDEO_BO_UNLOCK(player);
3264 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3268 /* get bo from list*/
3269 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3270 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3271 if (tmp && (tmp->used == FALSE)) {
3272 LOGD("found bo %p to use", tmp->bo);
3274 MMPLAYER_VIDEO_BO_UNLOCK(player);
3275 return tbm_bo_ref(tmp->bo);
3279 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3280 MMPLAYER_VIDEO_BO_UNLOCK(player);
3284 if (player->ini.video_bo_timeout <= 0) {
3285 MMPLAYER_VIDEO_BO_WAIT(player);
3287 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3288 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3295 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3297 mmplayer_t *player = (mmplayer_t *)data;
3299 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3301 /* send prerolled pkt */
3302 player->video_stream_prerolled = false;
3304 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3306 /* not to send prerolled pkt again */
3307 player->video_stream_prerolled = true;
3311 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3313 mmplayer_t *player = (mmplayer_t *)data;
3314 mmplayer_video_decoded_data_info_t *stream = NULL;
3315 GstMemory *mem = NULL;
3318 MMPLAYER_RETURN_IF_FAIL(player);
3319 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3321 if (player->video_stream_prerolled) {
3322 player->video_stream_prerolled = false;
3323 LOGD("skip the prerolled pkt not to send it again");
3327 /* clear stream data structure */
3328 stream = __mmplayer_create_stream_from_pad(pad);
3330 LOGE("failed to alloc stream");
3334 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3336 /* set size and timestamp */
3337 mem = gst_buffer_peek_memory(buffer, 0);
3338 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3339 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3341 /* check zero-copy */
3342 if (player->set_mode.video_zc &&
3343 player->set_mode.video_export &&
3344 gst_is_tizen_memory(mem)) {
3345 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3346 stream->internal_buffer = gst_buffer_ref(buffer);
3347 } else { /* sw codec */
3348 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3351 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3355 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3356 LOGE("failed to send video decoded data.");
3363 LOGE("release video stream resource.");
3364 if (gst_is_tizen_memory(mem)) {
3366 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3368 tbm_bo_unref(stream->bo[i]);
3371 /* unref gst buffer */
3372 if (stream->internal_buffer)
3373 gst_buffer_unref(stream->internal_buffer);
3376 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3378 MMPLAYER_FREEIF(stream);
3383 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3385 mmplayer_gst_element_t *videobin = NULL;
3388 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3390 videobin = player->pipeline->videobin;
3392 /* Set spatial media metadata and/or user settings to the element.
3394 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3395 "projection-type", player->video360_metadata.projection_type, NULL);
3397 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3398 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3400 if (player->video360_metadata.full_pano_width_pixels &&
3401 player->video360_metadata.full_pano_height_pixels &&
3402 player->video360_metadata.cropped_area_image_width &&
3403 player->video360_metadata.cropped_area_image_height) {
3404 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3405 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3406 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3407 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3408 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3409 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3410 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3414 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3415 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3416 "horizontal-fov", player->video360_horizontal_fov,
3417 "vertical-fov", player->video360_vertical_fov, NULL);
3420 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3421 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3422 "zoom", 1.0f / player->video360_zoom, NULL);
3425 if (player->video360_yaw_radians <= M_PI &&
3426 player->video360_yaw_radians >= -M_PI &&
3427 player->video360_pitch_radians <= M_PI_2 &&
3428 player->video360_pitch_radians >= -M_PI_2) {
3429 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3430 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3431 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3432 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3433 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3434 "pose-yaw", player->video360_metadata.init_view_heading,
3435 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3438 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439 "passthrough", !player->is_video360_enabled, NULL);
3446 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3448 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3449 GList *element_bucket = NULL;
3452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3454 /* create video360 filter */
3455 if (player->is_360_feature_enabled && player->is_content_spherical) {
3456 LOGD("create video360 element");
3457 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3458 __mmplayer_gst_set_video360_property(player);
3462 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3463 LOGD("skip creating the videoconv and rotator");
3464 return MM_ERROR_NONE;
3467 /* in case of sw codec & overlay surface type, except 360 playback.
3468 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3469 LOGD("create video converter: %s", video_csc);
3470 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3473 *bucket = element_bucket;
3475 return MM_ERROR_NONE;
3477 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3478 g_list_free(element_bucket);
3482 return MM_ERROR_PLAYER_INTERNAL;
3486 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3488 gchar *factory_name = NULL;
3490 switch (surface_type) {
3491 case MM_DISPLAY_SURFACE_OVERLAY:
3492 if (strlen(player->ini.videosink_element_overlay) > 0)
3493 factory_name = player->ini.videosink_element_overlay;
3495 case MM_DISPLAY_SURFACE_REMOTE:
3496 case MM_DISPLAY_SURFACE_NULL:
3497 if (strlen(player->ini.videosink_element_fake) > 0)
3498 factory_name = player->ini.videosink_element_fake;
3501 LOGE("unidentified surface type");
3505 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3506 return factory_name;
3510 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3512 gchar *factory_name = NULL;
3513 mmplayer_gst_element_t *videobin = NULL;
3518 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3520 videobin = player->pipeline->videobin;
3521 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3523 attrs = MMPLAYER_GET_ATTRS(player);
3525 LOGE("cannot get content attribute");
3526 return MM_ERROR_PLAYER_INTERNAL;
3529 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3530 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3531 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3533 /* support shard memory with S/W codec on HawkP */
3534 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3535 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3536 "use-tbm", use_tbm, NULL);
3540 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3541 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3544 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3546 LOGD("disable last-sample");
3547 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3550 if (player->set_mode.video_export) {
3552 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3553 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3554 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3556 _mmplayer_add_signal_connection(player,
3557 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3558 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3560 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3563 _mmplayer_add_signal_connection(player,
3564 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3565 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3567 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3571 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3572 return MM_ERROR_PLAYER_INTERNAL;
3574 if (videobin[MMPLAYER_V_SINK].gst) {
3575 GstPad *sink_pad = NULL;
3576 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3578 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3579 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3580 gst_object_unref(GST_OBJECT(sink_pad));
3582 LOGE("failed to get sink pad from videosink");
3586 return MM_ERROR_NONE;
3591 * - video overlay surface(arm/x86) : tizenwlsink
3594 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3597 GList *element_bucket = NULL;
3598 mmplayer_gst_element_t *first_element = NULL;
3599 mmplayer_gst_element_t *videobin = NULL;
3600 gchar *videosink_factory_name = NULL;
3603 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3606 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3608 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3610 player->pipeline->videobin = videobin;
3613 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3614 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3615 if (!videobin[MMPLAYER_V_BIN].gst) {
3616 LOGE("failed to create videobin");
3620 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3623 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3624 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3626 /* additional setting for sink plug-in */
3627 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3628 LOGE("failed to set video property");
3632 /* store it as it's sink element */
3633 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3635 /* adding created elements to bin */
3636 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3637 LOGE("failed to add elements");
3641 /* Linking elements in the bucket by added order */
3642 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3643 LOGE("failed to link elements");
3647 /* get first element's sinkpad for creating ghostpad */
3648 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3649 if (!first_element) {
3650 LOGE("failed to get first element from bucket");
3654 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3656 LOGE("failed to get pad from first element");
3660 /* create ghostpad */
3661 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3662 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3663 LOGE("failed to add ghostpad to videobin");
3666 gst_object_unref(pad);
3668 /* done. free allocated variables */
3669 g_list_free(element_bucket);
3673 return MM_ERROR_NONE;
3676 LOGE("ERROR : releasing videobin");
3677 g_list_free(element_bucket);
3680 gst_object_unref(GST_OBJECT(pad));
3682 /* release videobin with it's childs */
3683 if (videobin[MMPLAYER_V_BIN].gst)
3684 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3686 MMPLAYER_FREEIF(videobin);
3687 player->pipeline->videobin = NULL;
3689 return MM_ERROR_PLAYER_INTERNAL;
3693 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3695 GList *element_bucket = NULL;
3696 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3698 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3699 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3700 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3701 "signal-handoffs", FALSE,
3704 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3705 _mmplayer_add_signal_connection(player,
3706 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3707 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3709 G_CALLBACK(__mmplayer_update_subtitle),
3712 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3713 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3715 if (!player->play_subtitle) {
3716 LOGD("add textbin sink as sink element of whole pipeline.");
3717 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3720 /* adding created elements to bin */
3721 LOGD("adding created elements to bin");
3722 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3723 LOGE("failed to add elements");
3727 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3728 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3729 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3731 /* linking elements in the bucket by added order. */
3732 LOGD("Linking elements in the bucket by added order.");
3733 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3734 LOGE("failed to link elements");
3738 /* done. free allocated variables */
3739 g_list_free(element_bucket);
3741 if (textbin[MMPLAYER_T_QUEUE].gst) {
3743 GstPad *ghostpad = NULL;
3745 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3747 LOGE("failed to get sink pad of text queue");
3751 ghostpad = gst_ghost_pad_new("text_sink", pad);
3752 gst_object_unref(pad);
3755 LOGE("failed to create ghostpad of textbin");
3759 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3760 LOGE("failed to add ghostpad to textbin");
3761 gst_object_unref(ghostpad);
3766 return MM_ERROR_NONE;
3769 g_list_free(element_bucket);
3771 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3772 LOGE("remove textbin sink from sink list");
3773 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3776 /* release element at __mmplayer_gst_create_text_sink_bin */
3777 return MM_ERROR_PLAYER_INTERNAL;
3781 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3783 mmplayer_gst_element_t *textbin = NULL;
3784 GList *element_bucket = NULL;
3785 int surface_type = 0;
3790 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3793 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3795 LOGE("failed to allocate memory for textbin");
3796 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3800 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3801 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3802 if (!textbin[MMPLAYER_T_BIN].gst) {
3803 LOGE("failed to create textbin");
3808 player->pipeline->textbin = textbin;
3811 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3812 LOGD("surface type for subtitle : %d", surface_type);
3813 switch (surface_type) {
3814 case MM_DISPLAY_SURFACE_OVERLAY:
3815 case MM_DISPLAY_SURFACE_NULL:
3816 case MM_DISPLAY_SURFACE_REMOTE:
3817 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3818 LOGE("failed to make plain text elements");
3829 return MM_ERROR_NONE;
3833 LOGD("ERROR : releasing textbin");
3835 g_list_free(element_bucket);
3837 /* release signal */
3838 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3840 /* release element which are not added to bin */
3841 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3842 /* NOTE : skip bin */
3843 if (textbin[i].gst) {
3844 GstObject *parent = NULL;
3845 parent = gst_element_get_parent(textbin[i].gst);
3848 gst_object_unref(GST_OBJECT(textbin[i].gst));
3849 textbin[i].gst = NULL;
3851 gst_object_unref(GST_OBJECT(parent));
3856 /* release textbin with it's childs */
3857 if (textbin[MMPLAYER_T_BIN].gst)
3858 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3860 MMPLAYER_FREEIF(player->pipeline->textbin);
3861 player->pipeline->textbin = NULL;
3864 return MM_ERROR_PLAYER_INTERNAL;
3868 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3870 mmplayer_gst_element_t *mainbin = NULL;
3871 mmplayer_gst_element_t *textbin = NULL;
3872 MMHandleType attrs = 0;
3873 GstElement *subsrc = NULL;
3874 GstElement *subparse = NULL;
3875 gchar *subtitle_uri = NULL;
3876 const gchar *charset = NULL;
3882 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3884 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3886 mainbin = player->pipeline->mainbin;
3888 attrs = MMPLAYER_GET_ATTRS(player);
3890 LOGE("cannot get content attribute");
3891 return MM_ERROR_PLAYER_INTERNAL;
3894 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3895 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3896 LOGE("subtitle uri is not proper filepath.");
3897 return MM_ERROR_PLAYER_INVALID_URI;
3900 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3901 LOGE("failed to get storage info of subtitle path");
3902 return MM_ERROR_PLAYER_INVALID_URI;
3905 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3907 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3908 player->subtitle_language_list = NULL;
3909 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3911 /* create the subtitle source */
3912 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3914 LOGE("failed to create filesrc element");
3917 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3919 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3920 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3922 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3923 LOGW("failed to add queue");
3924 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3925 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3926 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3931 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3933 LOGE("failed to create subparse element");
3937 charset = _mmplayer_get_charset(subtitle_uri);
3939 LOGD("detected charset is %s", charset);
3940 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3943 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3944 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3946 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3947 LOGW("failed to add subparse");
3948 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3949 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3950 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3954 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3955 LOGW("failed to link subsrc and subparse");
3959 player->play_subtitle = TRUE;
3960 player->adjust_subtitle_pos = 0;
3962 LOGD("play subtitle using subtitle file");
3964 if (player->pipeline->textbin == NULL) {
3965 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3966 LOGE("failed to create text sink bin. continuing without text");
3970 textbin = player->pipeline->textbin;
3972 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3973 LOGW("failed to add textbin");
3975 /* release signal */
3976 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3978 /* release textbin with it's childs */
3979 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3980 MMPLAYER_FREEIF(player->pipeline->textbin);
3981 player->pipeline->textbin = textbin = NULL;
3985 LOGD("link text input selector and textbin ghost pad");
3987 player->textsink_linked = 1;
3988 player->external_text_idx = 0;
3989 LOGI("textsink is linked");
3991 textbin = player->pipeline->textbin;
3992 LOGD("text bin has been created. reuse it.");
3993 player->external_text_idx = 1;
3996 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3997 LOGW("failed to link subparse and textbin");
4001 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4003 LOGE("failed to get sink pad from textsink to probe data");
4007 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4008 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4010 gst_object_unref(pad);
4013 /* create dot. for debugging */
4014 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4017 return MM_ERROR_NONE;
4020 /* release text pipeline resource */
4021 player->textsink_linked = 0;
4023 /* release signal */
4024 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4026 if (player->pipeline->textbin) {
4027 LOGE("remove textbin");
4029 /* release textbin with it's childs */
4030 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4031 MMPLAYER_FREEIF(player->pipeline->textbin);
4032 player->pipeline->textbin = NULL;
4036 /* release subtitle elem */
4037 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4038 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4040 return MM_ERROR_PLAYER_INTERNAL;
4044 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4046 mmplayer_t *player = (mmplayer_t *)data;
4047 MMMessageParamType msg = {0, };
4048 GstClockTime duration = 0;
4049 gpointer text = NULL;
4050 guint text_size = 0;
4051 gboolean ret = TRUE;
4052 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4056 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4057 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4059 if (player->is_subtitle_force_drop) {
4060 LOGW("subtitle is dropped forcedly.");
4064 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4065 text = mapinfo.data;
4066 text_size = mapinfo.size;
4068 if (player->set_mode.subtitle_off) {
4069 LOGD("subtitle is OFF.");
4073 if (!text || (text_size == 0)) {
4074 LOGD("There is no subtitle to be displayed.");
4078 msg.data = (void *)text;
4080 duration = GST_BUFFER_DURATION(buffer);
4082 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4083 if (player->duration > GST_BUFFER_PTS(buffer))
4084 duration = player->duration - GST_BUFFER_PTS(buffer);
4087 LOGI("subtitle duration is invalid, subtitle duration change "
4088 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4090 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4092 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4094 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4095 gst_buffer_unmap(buffer, &mapinfo);
4102 static GstPadProbeReturn
4103 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4105 mmplayer_t *player = (mmplayer_t *)u_data;
4106 GstClockTime cur_timestamp = 0;
4107 gint64 adjusted_timestamp = 0;
4108 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4110 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4112 if (player->set_mode.subtitle_off) {
4113 LOGD("subtitle is OFF.");
4117 if (player->adjust_subtitle_pos == 0) {
4118 LOGD("nothing to do");
4122 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4123 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4125 if (adjusted_timestamp < 0) {
4126 LOGD("adjusted_timestamp under zero");
4131 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4132 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4133 GST_TIME_ARGS(cur_timestamp),
4134 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4136 return GST_PAD_PROBE_OK;
4140 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4144 /* check player and subtitlebin are created */
4145 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4148 if (position == 0) {
4149 LOGD("nothing to do");
4151 return MM_ERROR_NONE;
4154 /* check current postion */
4155 player->adjust_subtitle_pos = position;
4157 LOGD("save adjust_subtitle_pos in player");
4161 return MM_ERROR_NONE;
4165 * This function is to create audio or video pipeline for playing.
4167 * @param player [in] handle of player
4169 * @return This function returns zero on success.
4174 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4176 int ret = MM_ERROR_NONE;
4177 mmplayer_gst_element_t *mainbin = NULL;
4178 MMHandleType attrs = 0;
4181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4183 /* get profile attribute */
4184 attrs = MMPLAYER_GET_ATTRS(player);
4186 LOGE("failed to get content attribute");
4190 /* create pipeline handles */
4191 if (player->pipeline) {
4192 LOGE("pipeline should be released before create new one");
4196 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4197 if (player->pipeline == NULL)
4200 /* create mainbin */
4201 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4202 if (mainbin == NULL)
4205 /* create pipeline */
4206 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4207 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4208 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4209 LOGE("failed to create pipeline");
4214 player->pipeline->mainbin = mainbin;
4216 /* create the source and decoder elements */
4217 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4218 ret = _mmplayer_gst_build_es_pipeline(player);
4220 ret = _mmplayer_gst_build_pipeline(player);
4222 if (ret != MM_ERROR_NONE) {
4223 LOGE("failed to create some elements");
4227 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4228 if (__mmplayer_check_subtitle(player)
4229 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4230 LOGE("failed to create text pipeline");
4233 ret = _mmplayer_gst_add_bus_watch(player);
4234 if (ret != MM_ERROR_NONE) {
4235 LOGE("failed to add bus watch");
4240 return MM_ERROR_NONE;
4243 __mmplayer_gst_destroy_pipeline(player);
4244 return MM_ERROR_PLAYER_INTERNAL;
4248 __mmplayer_reset_gapless_state(mmplayer_t *player)
4251 MMPLAYER_RETURN_IF_FAIL(player
4253 && player->pipeline->audiobin
4254 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4256 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4263 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4266 int ret = MM_ERROR_NONE;
4270 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4272 /* cleanup stuffs */
4273 MMPLAYER_FREEIF(player->type);
4274 player->no_more_pad = FALSE;
4275 player->num_dynamic_pad = 0;
4276 player->demux_pad_index = 0;
4278 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4279 player->subtitle_language_list = NULL;
4280 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4282 __mmplayer_reset_gapless_state(player);
4284 if (player->streamer) {
4285 _mm_player_streaming_initialize(player->streamer, FALSE);
4286 _mm_player_streaming_destroy(player->streamer);
4287 player->streamer = NULL;
4290 /* cleanup unlinked mime type */
4291 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4292 MMPLAYER_FREEIF(player->unlinked_video_mime);
4293 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4295 /* cleanup running stuffs */
4296 _mmplayer_cancel_eos_timer(player);
4298 /* cleanup gst stuffs */
4299 if (player->pipeline) {
4300 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4301 GstTagList *tag_list = player->pipeline->tag_list;
4303 /* first we need to disconnect all signal hander */
4304 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4307 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4308 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4309 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4310 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4311 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4312 gst_object_unref(bus);
4314 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4315 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4316 if (ret != MM_ERROR_NONE) {
4317 LOGE("fail to change state to NULL");
4318 return MM_ERROR_PLAYER_INTERNAL;
4321 LOGW("succeeded in changing state to NULL");
4323 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4326 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4327 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4329 /* free avsysaudiosink
4330 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4331 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4333 MMPLAYER_FREEIF(audiobin);
4334 MMPLAYER_FREEIF(videobin);
4335 MMPLAYER_FREEIF(textbin);
4336 MMPLAYER_FREEIF(mainbin);
4340 gst_tag_list_unref(tag_list);
4342 MMPLAYER_FREEIF(player->pipeline);
4344 MMPLAYER_FREEIF(player->album_art);
4346 if (player->v_stream_caps) {
4347 gst_caps_unref(player->v_stream_caps);
4348 player->v_stream_caps = NULL;
4351 if (player->a_stream_caps) {
4352 gst_caps_unref(player->a_stream_caps);
4353 player->a_stream_caps = NULL;
4356 if (player->s_stream_caps) {
4357 gst_caps_unref(player->s_stream_caps);
4358 player->s_stream_caps = NULL;
4360 _mmplayer_track_destroy(player);
4362 if (player->sink_elements)
4363 g_list_free(player->sink_elements);
4364 player->sink_elements = NULL;
4366 if (player->bufmgr) {
4367 tbm_bufmgr_deinit(player->bufmgr);
4368 player->bufmgr = NULL;
4371 LOGW("finished destroy pipeline");
4379 __mmplayer_gst_realize(mmplayer_t *player)
4382 int ret = MM_ERROR_NONE;
4386 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4388 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4390 ret = __mmplayer_gst_create_pipeline(player);
4392 LOGE("failed to create pipeline");
4396 /* set pipeline state to READY */
4397 /* NOTE : state change to READY must be performed sync. */
4398 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4399 ret = _mmplayer_gst_set_state(player,
4400 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4402 if (ret != MM_ERROR_NONE) {
4403 /* return error if failed to set state */
4404 LOGE("failed to set READY state");
4408 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4410 /* create dot before error-return. for debugging */
4411 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4419 __mmplayer_gst_unrealize(mmplayer_t *player)
4421 int ret = MM_ERROR_NONE;
4425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4427 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4428 MMPLAYER_PRINT_STATE(player);
4430 /* release miscellaneous information */
4431 __mmplayer_release_misc(player);
4433 /* destroy pipeline */
4434 ret = __mmplayer_gst_destroy_pipeline(player);
4435 if (ret != MM_ERROR_NONE) {
4436 LOGE("failed to destory pipeline");
4440 /* release miscellaneous information.
4441 these info needs to be released after pipeline is destroyed. */
4442 __mmplayer_release_misc_post(player);
4444 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4452 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4457 LOGW("set_message_callback is called with invalid player handle");
4458 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4461 player->msg_cb = callback;
4462 player->msg_cb_param = user_param;
4464 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4468 return MM_ERROR_NONE;
4472 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4474 int ret = MM_ERROR_NONE;
4479 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4480 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4481 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4483 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4485 if (strstr(uri, "es_buff://")) {
4486 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4487 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4488 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4489 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4491 tmp = g_ascii_strdown(uri, strlen(uri));
4492 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4493 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4495 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4497 } else if (strstr(uri, "mms://")) {
4498 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4499 } else if ((path = strstr(uri, "mem://"))) {
4500 ret = __mmplayer_set_mem_uri(data, path, param);
4502 ret = __mmplayer_set_file_uri(data, uri);
4505 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4506 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4507 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4508 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4510 /* dump parse result */
4511 SECURE_LOGW("incoming uri : %s", uri);
4512 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4513 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4521 __mmplayer_can_do_interrupt(mmplayer_t *player)
4523 if (!player || !player->pipeline || !player->attrs) {
4524 LOGW("not initialized");
4528 if (player->audio_decoded_cb) {
4529 LOGW("not support in pcm extraction mode");
4533 /* check if seeking */
4534 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4535 MMMessageParamType msg_param;
4536 memset(&msg_param, 0, sizeof(MMMessageParamType));
4537 msg_param.code = MM_ERROR_PLAYER_SEEK;
4538 player->seek_state = MMPLAYER_SEEK_NONE;
4539 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4543 /* check other thread */
4544 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4545 LOGW("locked already, cmd state : %d", player->cmd);
4547 /* check application command */
4548 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4549 LOGW("playing.. should wait cmd lock then, will be interrupted");
4551 /* lock will be released at mrp_resource_release_cb() */
4552 MMPLAYER_CMD_LOCK(player);
4555 LOGW("nothing to do");
4558 LOGW("can interrupt immediately");
4562 FAILED: /* with CMD UNLOCKED */
4565 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4570 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4573 mmplayer_t *player = NULL;
4574 MMMessageParamType msg = {0, };
4576 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4581 LOGE("user_data is null");
4584 player = (mmplayer_t *)user_data;
4586 if (!__mmplayer_can_do_interrupt(player)) {
4587 LOGW("no need to interrupt, so leave");
4588 /* FIXME: there is no way to avoid releasing resource. */
4592 player->interrupted_by_resource = TRUE;
4594 /* get last play position */
4595 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4596 msg.union_type = MM_MSG_UNION_TIME;
4597 msg.time.elapsed = pos;
4598 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4600 LOGW("failed to get play position.");
4603 LOGD("video resource conflict so, resource will be freed by unrealizing");
4604 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4605 LOGE("failed to unrealize");
4607 /* lock is called in __mmplayer_can_do_interrupt() */
4608 MMPLAYER_CMD_UNLOCK(player);
4610 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4611 player->hw_resource[res_idx] = NULL;
4615 return TRUE; /* release all the resources */
4619 __mmplayer_initialize_video_roi(mmplayer_t *player)
4621 player->video_roi.scale_x = 0.0;
4622 player->video_roi.scale_y = 0.0;
4623 player->video_roi.scale_width = 1.0;
4624 player->video_roi.scale_height = 1.0;
4628 _mmplayer_create_player(MMHandleType handle)
4630 int ret = MM_ERROR_PLAYER_INTERNAL;
4631 bool enabled = false;
4633 mmplayer_t *player = MM_PLAYER_CAST(handle);
4637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4639 /* initialize player state */
4640 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4641 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4642 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4643 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4645 /* check current state */
4646 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4648 /* construct attributes */
4649 player->attrs = _mmplayer_construct_attribute(handle);
4651 if (!player->attrs) {
4652 LOGE("Failed to construct attributes");
4656 /* initialize gstreamer with configured parameter */
4657 if (!__mmplayer_init_gstreamer(player)) {
4658 LOGE("Initializing gstreamer failed");
4659 _mmplayer_deconstruct_attribute(handle);
4663 /* create lock. note that g_tread_init() has already called in gst_init() */
4664 g_mutex_init(&player->fsink_lock);
4666 /* create update tag lock */
4667 g_mutex_init(&player->update_tag_lock);
4669 /* create gapless play mutex */
4670 g_mutex_init(&player->gapless_play_thread_mutex);
4672 /* create gapless play cond */
4673 g_cond_init(&player->gapless_play_thread_cond);
4675 /* create gapless play thread */
4676 player->gapless_play_thread =
4677 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4678 if (!player->gapless_play_thread) {
4679 LOGE("failed to create gapless play thread");
4680 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4681 g_mutex_clear(&player->gapless_play_thread_mutex);
4682 g_cond_clear(&player->gapless_play_thread_cond);
4686 player->bus_msg_q = g_queue_new();
4687 if (!player->bus_msg_q) {
4688 LOGE("failed to create queue for bus_msg");
4689 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4693 ret = _mmplayer_initialize_video_capture(player);
4694 if (ret != MM_ERROR_NONE) {
4695 LOGE("failed to initialize video capture");
4699 /* initialize resource manager */
4700 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4701 __resource_release_cb, player, &player->resource_manager)
4702 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4703 LOGE("failed to initialize resource manager");
4704 ret = MM_ERROR_PLAYER_INTERNAL;
4708 /* create video bo lock and cond */
4709 g_mutex_init(&player->video_bo_mutex);
4710 g_cond_init(&player->video_bo_cond);
4712 /* create media stream callback mutex */
4713 g_mutex_init(&player->media_stream_cb_lock);
4715 /* create subtitle info lock and cond */
4716 g_mutex_init(&player->subtitle_info_mutex);
4717 g_cond_init(&player->subtitle_info_cond);
4719 player->streaming_type = STREAMING_SERVICE_NONE;
4721 /* give default value of audio effect setting */
4722 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4723 player->sound.rg_enable = false;
4724 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4726 player->play_subtitle = FALSE;
4727 player->has_closed_caption = FALSE;
4728 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4729 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4730 player->pending_resume = FALSE;
4731 if (player->ini.dump_element_keyword[0][0] == '\0')
4732 player->ini.set_dump_element_flag = FALSE;
4734 player->ini.set_dump_element_flag = TRUE;
4736 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4737 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4738 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4740 /* Set video360 settings to their defaults for just-created player.
4743 player->is_360_feature_enabled = FALSE;
4744 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4745 LOGI("spherical feature info: %d", enabled);
4747 player->is_360_feature_enabled = TRUE;
4749 LOGE("failed to get spherical feature info");
4752 player->is_content_spherical = FALSE;
4753 player->is_video360_enabled = TRUE;
4754 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4755 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4756 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4757 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4758 player->video360_zoom = 1.0f;
4759 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4760 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4762 __mmplayer_initialize_video_roi(player);
4764 /* set player state to null */
4765 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4766 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4770 return MM_ERROR_NONE;
4774 g_mutex_clear(&player->fsink_lock);
4775 /* free update tag lock */
4776 g_mutex_clear(&player->update_tag_lock);
4777 g_queue_free(player->bus_msg_q);
4778 player->bus_msg_q = NULL;
4779 /* free gapless play thread */
4780 if (player->gapless_play_thread) {
4781 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4782 player->gapless_play_thread_exit = TRUE;
4783 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4784 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4786 g_thread_join(player->gapless_play_thread);
4787 player->gapless_play_thread = NULL;
4789 g_mutex_clear(&player->gapless_play_thread_mutex);
4790 g_cond_clear(&player->gapless_play_thread_cond);
4793 /* release attributes */
4794 _mmplayer_deconstruct_attribute(handle);
4802 __mmplayer_init_gstreamer(mmplayer_t *player)
4804 static gboolean initialized = FALSE;
4805 static const int max_argc = 50;
4807 gchar **argv = NULL;
4808 gchar **argv2 = NULL;
4814 LOGD("gstreamer already initialized.");
4819 argc = malloc(sizeof(int));
4820 argv = malloc(sizeof(gchar *) * max_argc);
4821 argv2 = malloc(sizeof(gchar *) * max_argc);
4823 if (!argc || !argv || !argv2)
4826 memset(argv, 0, sizeof(gchar *) * max_argc);
4827 memset(argv2, 0, sizeof(gchar *) * max_argc);
4831 argv[0] = g_strdup("mmplayer");
4834 for (i = 0; i < 5; i++) {
4835 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4836 if (strlen(player->ini.gst_param[i]) > 0) {
4837 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4842 /* we would not do fork for scanning plugins */
4843 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4846 /* check disable registry scan */
4847 if (player->ini.skip_rescan) {
4848 argv[*argc] = g_strdup("--gst-disable-registry-update");
4852 /* check disable segtrap */
4853 if (player->ini.disable_segtrap) {
4854 argv[*argc] = g_strdup("--gst-disable-segtrap");
4858 LOGD("initializing gstreamer with following parameter");
4859 LOGD("argc : %d", *argc);
4862 for (i = 0; i < arg_count; i++) {
4864 LOGD("argv[%d] : %s", i, argv2[i]);
4867 /* initializing gstreamer */
4868 if (!gst_init_check(argc, &argv, &err)) {
4869 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4876 for (i = 0; i < arg_count; i++) {
4877 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4878 MMPLAYER_FREEIF(argv2[i]);
4881 MMPLAYER_FREEIF(argv);
4882 MMPLAYER_FREEIF(argv2);
4883 MMPLAYER_FREEIF(argc);
4893 for (i = 0; i < arg_count; i++) {
4894 LOGD("free[%d] : %s", i, argv2[i]);
4895 MMPLAYER_FREEIF(argv2[i]);
4898 MMPLAYER_FREEIF(argv);
4899 MMPLAYER_FREEIF(argv2);
4900 MMPLAYER_FREEIF(argc);
4906 __mmplayer_check_async_state_transition(mmplayer_t *player)
4908 GstState element_state = GST_STATE_VOID_PENDING;
4909 GstState element_pending_state = GST_STATE_VOID_PENDING;
4910 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4911 GstElement *element = NULL;
4912 gboolean async = FALSE;
4914 /* check player handle */
4915 MMPLAYER_RETURN_IF_FAIL(player &&
4917 player->pipeline->mainbin &&
4918 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4921 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4923 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4924 LOGD("don't need to check the pipeline state");
4928 MMPLAYER_PRINT_STATE(player);
4930 /* wait for state transition */
4931 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4932 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4934 if (ret == GST_STATE_CHANGE_FAILURE) {
4935 LOGE(" [%s] state : %s pending : %s",
4936 GST_ELEMENT_NAME(element),
4937 gst_element_state_get_name(element_state),
4938 gst_element_state_get_name(element_pending_state));
4940 /* dump state of all element */
4941 _mmplayer_dump_pipeline_state(player);
4946 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4951 _mmplayer_destroy(MMHandleType handle)
4953 mmplayer_t *player = MM_PLAYER_CAST(handle);
4957 /* check player handle */
4958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4960 /* destroy can called at anytime */
4961 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4963 /* check async state transition */
4964 __mmplayer_check_async_state_transition(player);
4966 /* release gapless play thread */
4967 if (player->gapless_play_thread) {
4968 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4969 player->gapless_play_thread_exit = TRUE;
4970 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4971 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4973 LOGD("waitting for gapless play thread exit");
4974 g_thread_join(player->gapless_play_thread);
4975 g_mutex_clear(&player->gapless_play_thread_mutex);
4976 g_cond_clear(&player->gapless_play_thread_cond);
4977 LOGD("gapless play thread released");
4980 _mmplayer_release_video_capture(player);
4982 /* de-initialize resource manager */
4983 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4984 player->resource_manager))
4985 LOGE("failed to deinitialize resource manager");
4987 /* release pipeline */
4988 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4989 LOGE("failed to destory pipeline");
4990 return MM_ERROR_PLAYER_INTERNAL;
4993 g_queue_free(player->bus_msg_q);
4995 /* release subtitle info lock and cond */
4996 g_mutex_clear(&player->subtitle_info_mutex);
4997 g_cond_clear(&player->subtitle_info_cond);
4999 __mmplayer_release_dump_list(player->dump_list);
5001 /* release miscellaneous information */
5002 __mmplayer_release_misc(player);
5004 /* release miscellaneous information.
5005 these info needs to be released after pipeline is destroyed. */
5006 __mmplayer_release_misc_post(player);
5008 /* release attributes */
5009 _mmplayer_deconstruct_attribute(handle);
5012 g_mutex_clear(&player->fsink_lock);
5015 g_mutex_clear(&player->update_tag_lock);
5017 /* release video bo lock and cond */
5018 g_mutex_clear(&player->video_bo_mutex);
5019 g_cond_clear(&player->video_bo_cond);
5021 /* release media stream callback lock */
5022 g_mutex_clear(&player->media_stream_cb_lock);
5026 return MM_ERROR_NONE;
5030 _mmplayer_realize(MMHandleType hplayer)
5032 mmplayer_t *player = (mmplayer_t *)hplayer;
5035 MMHandleType attrs = 0;
5036 int ret = MM_ERROR_NONE;
5040 /* check player handle */
5041 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5043 /* check current state */
5044 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5046 attrs = MMPLAYER_GET_ATTRS(player);
5048 LOGE("fail to get attributes.");
5049 return MM_ERROR_PLAYER_INTERNAL;
5051 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5052 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5054 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5055 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5057 if (ret != MM_ERROR_NONE) {
5058 LOGE("failed to parse profile");
5063 if (uri && (strstr(uri, "es_buff://"))) {
5064 if (strstr(uri, "es_buff://push_mode"))
5065 player->es_player_push_mode = TRUE;
5067 player->es_player_push_mode = FALSE;
5070 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5071 LOGW("mms protocol is not supported format.");
5072 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5075 if (MMPLAYER_IS_STREAMING(player))
5076 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5078 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5080 player->smooth_streaming = FALSE;
5081 player->videodec_linked = 0;
5082 player->audiodec_linked = 0;
5083 player->textsink_linked = 0;
5084 player->is_external_subtitle_present = FALSE;
5085 player->is_external_subtitle_added_now = FALSE;
5086 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5087 player->video360_metadata.is_spherical = -1;
5088 player->is_openal_plugin_used = FALSE;
5089 player->demux_pad_index = 0;
5090 player->subtitle_language_list = NULL;
5091 player->is_subtitle_force_drop = FALSE;
5093 _mmplayer_track_initialize(player);
5094 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5096 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5097 gint prebuffer_ms = 0, rebuffer_ms = 0;
5099 player->streamer = _mm_player_streaming_create();
5100 _mm_player_streaming_initialize(player->streamer, TRUE);
5102 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5103 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5105 if (prebuffer_ms > 0) {
5106 prebuffer_ms = MAX(prebuffer_ms, 1000);
5107 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5110 if (rebuffer_ms > 0) {
5111 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5112 rebuffer_ms = MAX(rebuffer_ms, 1000);
5113 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5116 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5117 player->streamer->buffering_req.rebuffer_time);
5120 /* realize pipeline */
5121 ret = __mmplayer_gst_realize(player);
5122 if (ret != MM_ERROR_NONE)
5123 LOGE("fail to realize the player.");
5125 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5133 _mmplayer_unrealize(MMHandleType hplayer)
5135 mmplayer_t *player = (mmplayer_t *)hplayer;
5136 int ret = MM_ERROR_NONE;
5140 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5142 MMPLAYER_CMD_UNLOCK(player);
5143 /* destroy the gst bus msg thread which is created during realize.
5144 this funct have to be called before getting cmd lock. */
5145 _mmplayer_bus_msg_thread_destroy(player);
5146 MMPLAYER_CMD_LOCK(player);
5148 /* check current state */
5149 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5151 /* check async state transition */
5152 __mmplayer_check_async_state_transition(player);
5154 /* unrealize pipeline */
5155 ret = __mmplayer_gst_unrealize(player);
5157 if (!player->interrupted_by_resource) {
5158 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5159 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5160 LOGE("failed to release video resources");
5168 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5170 mmplayer_t *player = (mmplayer_t *)hplayer;
5172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5174 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5178 _mmplayer_get_state(MMHandleType hplayer, int *state)
5180 mmplayer_t *player = (mmplayer_t *)hplayer;
5182 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5184 *state = MMPLAYER_CURRENT_STATE(player);
5186 return MM_ERROR_NONE;
5190 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5192 GstElement *vol_element = NULL;
5193 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5197 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5199 /* check pipeline handle */
5200 if (!player->pipeline || !player->pipeline->audiobin) {
5201 LOGD("'%s' will be applied when audiobin is created", prop_name);
5203 /* NOTE : stored value will be used in create_audiobin
5204 * returning MM_ERROR_NONE here makes application to able to
5205 * set audio volume or mute at anytime.
5207 return MM_ERROR_NONE;
5210 if (player->build_audio_offload) {
5211 LOGD("offload pipeline");
5212 volume_elem_id = MMPLAYER_A_SINK;
5215 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5217 LOGE("failed to get vol element %d", volume_elem_id);
5218 return MM_ERROR_PLAYER_INTERNAL;
5221 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5223 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5224 LOGE("there is no '%s' property", prop_name);
5225 return MM_ERROR_PLAYER_INTERNAL;
5228 if (!strcmp(prop_name, "volume")) {
5229 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5230 } else if (!strcmp(prop_name, "mute")) {
5231 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5233 LOGE("invalid property %s", prop_name);
5234 return MM_ERROR_PLAYER_INTERNAL;
5237 return MM_ERROR_NONE;
5241 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5243 int ret = MM_ERROR_NONE;
5244 mmplayer_t *player = (mmplayer_t *)hplayer;
5247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5249 LOGD("volume = %f", volume);
5251 /* invalid factor range or not */
5252 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5253 LOGE("Invalid volume value");
5254 return MM_ERROR_INVALID_ARGUMENT;
5257 player->sound.volume = volume;
5259 ret = __mmplayer_gst_set_volume_property(player, "volume");
5266 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5268 mmplayer_t *player = (mmplayer_t *)hplayer;
5272 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5275 *volume = player->sound.volume;
5277 LOGD("current vol = %f", *volume);
5280 return MM_ERROR_NONE;
5284 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5286 int ret = MM_ERROR_NONE;
5287 mmplayer_t *player = (mmplayer_t *)hplayer;
5290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 LOGD("mute = %d", mute);
5294 player->sound.mute = mute;
5296 ret = __mmplayer_gst_set_volume_property(player, "mute");
5303 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5305 mmplayer_t *player = (mmplayer_t *)hplayer;
5309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5310 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5312 *mute = player->sound.mute;
5314 LOGD("current mute = %d", *mute);
5318 return MM_ERROR_NONE;
5322 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5324 mmplayer_t *player = (mmplayer_t *)hplayer;
5328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5330 player->video_stream_changed_cb = callback;
5331 player->video_stream_changed_cb_user_param = user_param;
5332 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5336 return MM_ERROR_NONE;
5340 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5342 mmplayer_t *player = (mmplayer_t *)hplayer;
5346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5348 player->audio_stream_changed_cb = callback;
5349 player->audio_stream_changed_cb_user_param = user_param;
5350 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5354 return MM_ERROR_NONE;
5358 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5360 mmplayer_t *player = (mmplayer_t *)hplayer;
5364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5366 player->audio_decoded_cb = callback;
5367 player->audio_decoded_cb_user_param = user_param;
5368 player->audio_extract_opt = opt;
5369 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5373 return MM_ERROR_NONE;
5377 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5379 mmplayer_t *player = (mmplayer_t *)hplayer;
5383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5385 if (callback && !player->bufmgr)
5386 player->bufmgr = tbm_bufmgr_init(-1);
5388 player->set_mode.video_export = (callback) ? true : false;
5389 player->video_decoded_cb = callback;
5390 player->video_decoded_cb_user_param = user_param;
5392 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5396 return MM_ERROR_NONE;
5400 _mmplayer_start(MMHandleType hplayer)
5402 mmplayer_t *player = (mmplayer_t *)hplayer;
5403 gint ret = MM_ERROR_NONE;
5407 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5409 /* check current state */
5410 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5412 /* start pipeline */
5413 ret = _mmplayer_gst_start(player);
5414 if (ret != MM_ERROR_NONE)
5415 LOGE("failed to start player.");
5417 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5418 LOGD("force playing start even during buffering");
5419 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5427 /* NOTE: post "not supported codec message" to application
5428 * when one codec is not found during AUTOPLUGGING in MSL.
5429 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5430 * And, if any codec is not found, don't send message here.
5431 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5434 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5436 MMMessageParamType msg_param;
5437 memset(&msg_param, 0, sizeof(MMMessageParamType));
5438 gboolean post_msg_direct = FALSE;
5442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5444 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5445 player->not_supported_codec, player->can_support_codec);
5447 if (player->not_found_demuxer) {
5448 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5449 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5451 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5452 MMPLAYER_FREEIF(msg_param.data);
5454 return MM_ERROR_NONE;
5457 if (player->not_supported_codec) {
5458 if (player->can_support_codec) {
5459 // There is one codec to play
5460 post_msg_direct = TRUE;
5462 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5463 post_msg_direct = TRUE;
5466 if (post_msg_direct) {
5467 MMMessageParamType msg_param;
5468 memset(&msg_param, 0, sizeof(MMMessageParamType));
5470 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5471 LOGW("not found AUDIO codec, posting error code to application.");
5473 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5474 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5475 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5476 LOGW("not found VIDEO codec, posting error code to application.");
5478 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5479 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5482 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5484 MMPLAYER_FREEIF(msg_param.data);
5486 return MM_ERROR_NONE;
5488 // no any supported codec case
5489 LOGW("not found any codec, posting error code to application.");
5491 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5492 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5493 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5495 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5496 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5499 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5501 MMPLAYER_FREEIF(msg_param.data);
5507 return MM_ERROR_NONE;
5511 __mmplayer_check_pipeline(mmplayer_t *player)
5513 GstState element_state = GST_STATE_VOID_PENDING;
5514 GstState element_pending_state = GST_STATE_VOID_PENDING;
5516 int ret = MM_ERROR_NONE;
5518 if (!player->gapless.reconfigure)
5521 LOGW("pipeline is under construction.");
5523 MMPLAYER_PLAYBACK_LOCK(player);
5524 MMPLAYER_PLAYBACK_UNLOCK(player);
5526 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5528 /* wait for state transition */
5529 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5530 if (ret == GST_STATE_CHANGE_FAILURE)
5531 LOGE("failed to change pipeline state within %d sec", timeout);
5534 /* NOTE : it should be able to call 'stop' anytime*/
5536 _mmplayer_stop(MMHandleType hplayer)
5538 mmplayer_t *player = (mmplayer_t *)hplayer;
5539 int ret = MM_ERROR_NONE;
5543 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5545 /* check current state */
5546 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5548 /* check pipline building state */
5549 __mmplayer_check_pipeline(player);
5550 __mmplayer_reset_gapless_state(player);
5552 /* NOTE : application should not wait for EOS after calling STOP */
5553 _mmplayer_cancel_eos_timer(player);
5556 player->seek_state = MMPLAYER_SEEK_NONE;
5559 ret = _mmplayer_gst_stop(player);
5561 if (ret != MM_ERROR_NONE)
5562 LOGE("failed to stop player.");
5570 _mmplayer_pause(MMHandleType hplayer)
5572 mmplayer_t *player = (mmplayer_t *)hplayer;
5573 gint64 pos_nsec = 0;
5574 gboolean async = FALSE;
5575 gint ret = MM_ERROR_NONE;
5579 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5581 /* check current state */
5582 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5584 /* check pipline building state */
5585 __mmplayer_check_pipeline(player);
5587 switch (MMPLAYER_CURRENT_STATE(player)) {
5588 case MM_PLAYER_STATE_READY:
5590 /* check prepare async or not.
5591 * In the case of streaming playback, it's recommned to avoid blocking wait.
5593 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5594 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5596 /* Changing back sync of rtspsrc to async */
5597 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5598 LOGD("async prepare working mode for rtsp");
5604 case MM_PLAYER_STATE_PLAYING:
5606 /* NOTE : store current point to overcome some bad operation
5607 *(returning zero when getting current position in paused state) of some
5610 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5611 LOGW("getting current position failed in paused");
5613 player->last_position = pos_nsec;
5615 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5616 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5617 This causes problem is position calculation during normal pause resume scenarios also.
5618 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5619 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5620 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5621 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5627 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5628 LOGD("doing async pause in case of ms buff src");
5632 /* pause pipeline */
5633 ret = _mmplayer_gst_pause(player, async);
5635 if (ret != MM_ERROR_NONE)
5636 LOGE("failed to pause player. ret : 0x%x", ret);
5638 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5639 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5640 LOGE("failed to update display_rotation");
5648 /* in case of streaming, pause could take long time.*/
5650 _mmplayer_abort_pause(MMHandleType hplayer)
5652 mmplayer_t *player = (mmplayer_t *)hplayer;
5653 int ret = MM_ERROR_NONE;
5657 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5659 player->pipeline->mainbin,
5660 MM_ERROR_PLAYER_NOT_INITIALIZED);
5662 LOGD("set the pipeline state to READY");
5664 /* set state to READY */
5665 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5666 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5667 if (ret != MM_ERROR_NONE) {
5668 LOGE("fail to change state to READY");
5669 return MM_ERROR_PLAYER_INTERNAL;
5672 LOGD("succeeded in changing state to READY");
5677 _mmplayer_resume(MMHandleType hplayer)
5679 mmplayer_t *player = (mmplayer_t *)hplayer;
5680 int ret = MM_ERROR_NONE;
5681 gboolean async = FALSE;
5685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5687 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5688 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5689 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5693 /* Changing back sync mode rtspsrc to async */
5694 LOGD("async resume for rtsp case");
5698 /* check current state */
5699 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5701 ret = _mmplayer_gst_resume(player, async);
5702 if (ret != MM_ERROR_NONE)
5703 LOGE("failed to resume player.");
5705 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5706 LOGD("force resume even during buffering");
5707 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5716 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5718 mmplayer_t *player = (mmplayer_t *)hplayer;
5719 gint64 pos_nsec = 0;
5720 int ret = MM_ERROR_NONE;
5722 signed long long start = 0, stop = 0;
5723 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5726 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5727 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5729 /* The sound of video is not supported under 0.0 and over 2.0. */
5730 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5731 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5734 _mmplayer_set_mute(hplayer, mute);
5736 if (player->playback_rate == rate)
5737 return MM_ERROR_NONE;
5739 /* If the position is reached at start potion during fast backward, EOS is posted.
5740 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5742 player->playback_rate = rate;
5744 current_state = MMPLAYER_CURRENT_STATE(player);
5746 if (current_state != MM_PLAYER_STATE_PAUSED)
5747 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5749 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5751 if ((current_state == MM_PLAYER_STATE_PAUSED)
5752 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5753 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5754 pos_nsec = player->last_position;
5759 stop = GST_CLOCK_TIME_NONE;
5761 start = GST_CLOCK_TIME_NONE;
5765 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5766 player->playback_rate,
5768 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5769 GST_SEEK_TYPE_SET, start,
5770 GST_SEEK_TYPE_SET, stop)) {
5771 LOGE("failed to set speed playback");
5772 return MM_ERROR_PLAYER_SEEK;
5775 LOGD("succeeded to set speed playback as %0.1f", rate);
5779 return MM_ERROR_NONE;;
5783 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5785 mmplayer_t *player = (mmplayer_t *)hplayer;
5786 int ret = MM_ERROR_NONE;
5790 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5792 /* check pipline building state */
5793 __mmplayer_check_pipeline(player);
5795 ret = _mmplayer_gst_set_position(player, position, FALSE);
5803 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5805 mmplayer_t *player = (mmplayer_t *)hplayer;
5806 int ret = MM_ERROR_NONE;
5808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5809 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5811 if (g_strrstr(player->type, "video/mpegts"))
5812 __mmplayer_update_duration_value(player);
5814 *duration = player->duration;
5819 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5821 mmplayer_t *player = (mmplayer_t *)hplayer;
5822 int ret = MM_ERROR_NONE;
5824 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5826 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5832 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5834 mmplayer_t *player = (mmplayer_t *)hplayer;
5835 int ret = MM_ERROR_NONE;
5839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5841 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5849 __mmplayer_is_midi_type(gchar *str_caps)
5851 if ((g_strrstr(str_caps, "audio/midi")) ||
5852 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5853 (g_strrstr(str_caps, "application/x-smaf")) ||
5854 (g_strrstr(str_caps, "audio/x-imelody")) ||
5855 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5856 (g_strrstr(str_caps, "audio/xmf")) ||
5857 (g_strrstr(str_caps, "audio/mxmf"))) {
5866 __mmplayer_is_only_mp3_type(gchar *str_caps)
5868 if (g_strrstr(str_caps, "application/x-id3") ||
5869 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5875 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5877 GstStructure *caps_structure = NULL;
5878 gint samplerate = 0;
5882 MMPLAYER_RETURN_IF_FAIL(player && caps);
5884 caps_structure = gst_caps_get_structure(caps, 0);
5886 /* set stream information */
5887 gst_structure_get_int(caps_structure, "rate", &samplerate);
5888 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5890 gst_structure_get_int(caps_structure, "channels", &channels);
5891 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5893 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5897 __mmplayer_update_content_type_info(mmplayer_t *player)
5900 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5902 if (__mmplayer_is_midi_type(player->type)) {
5903 player->bypass_audio_effect = TRUE;
5907 if (!player->streamer) {
5908 LOGD("no need to check streaming type");
5912 if (g_strrstr(player->type, "application/x-hls")) {
5913 /* If it can't know exact type when it parses uri because of redirection case,
5914 * it will be fixed by typefinder or when doing autoplugging.
5916 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5917 player->streamer->is_adaptive_streaming = TRUE;
5918 } else if (g_strrstr(player->type, "application/dash+xml")) {
5919 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5920 player->streamer->is_adaptive_streaming = TRUE;
5923 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5924 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5925 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5927 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5928 if (player->streamer->is_adaptive_streaming)
5929 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5931 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5935 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5940 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5941 GstCaps *caps, gpointer data)
5943 mmplayer_t *player = (mmplayer_t *)data;
5948 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5950 /* store type string */
5951 MMPLAYER_FREEIF(player->type);
5952 player->type = gst_caps_to_string(caps);
5954 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5955 player, player->type, probability, gst_caps_get_size(caps));
5957 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5958 (g_strrstr(player->type, "audio/x-raw-int"))) {
5959 LOGE("not support media format");
5961 if (player->msg_posted == FALSE) {
5962 MMMessageParamType msg_param;
5963 memset(&msg_param, 0, sizeof(MMMessageParamType));
5965 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5966 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5968 /* don't post more if one was sent already */
5969 player->msg_posted = TRUE;
5974 __mmplayer_update_content_type_info(player);
5976 pad = gst_element_get_static_pad(tf, "src");
5978 LOGE("fail to get typefind src pad.");
5982 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5983 gboolean async = FALSE;
5984 LOGE("failed to autoplug %s", player->type);
5986 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5988 if (async && player->msg_posted == FALSE)
5989 __mmplayer_handle_missed_plugin(player);
5993 gst_object_unref(GST_OBJECT(pad));
6001 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6003 GstElement *decodebin = NULL;
6007 /* create decodebin */
6008 decodebin = gst_element_factory_make("decodebin", NULL);
6011 LOGE("fail to create decodebin");
6015 /* raw pad handling signal */
6016 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6017 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6019 /* no-more-pad pad handling signal */
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6021 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6023 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6024 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6026 /* This signal is emitted when a pad for which there is no further possible
6027 decoding is added to the decodebin.*/
6028 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6029 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6031 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6032 before looking for any elements that can handle that stream.*/
6033 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6034 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6036 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6037 before looking for any elements that can handle that stream.*/
6038 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6039 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6041 /* This signal is emitted once decodebin has finished decoding all the data.*/
6042 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6043 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6045 /* This signal is emitted when a element is added to the bin.*/
6046 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6047 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6054 __mmplayer_gst_make_queue2(mmplayer_t *player)
6056 GstElement *queue2 = NULL;
6057 gint64 dur_bytes = 0L;
6058 mmplayer_gst_element_t *mainbin = NULL;
6059 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6062 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6064 mainbin = player->pipeline->mainbin;
6066 queue2 = gst_element_factory_make("queue2", "queue2");
6068 LOGE("failed to create buffering queue element");
6072 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6073 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6075 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6077 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6078 * skip the pull mode(file or ring buffering) setting. */
6079 if (dur_bytes > 0) {
6080 if (!g_strrstr(player->type, "video/mpegts")) {
6081 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6082 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6088 _mm_player_streaming_set_queue2(player->streamer,
6092 (guint64)dur_bytes); /* no meaning at the moment */
6098 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6100 mmplayer_gst_element_t *mainbin = NULL;
6101 GstElement *decodebin = NULL;
6102 GstElement *queue2 = NULL;
6103 GstPad *sinkpad = NULL;
6104 GstPad *qsrcpad = NULL;
6107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6109 mainbin = player->pipeline->mainbin;
6111 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6113 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6114 LOGW("need to check: muxed buffer is not null");
6117 queue2 = __mmplayer_gst_make_queue2(player);
6119 LOGE("failed to make queue2");
6123 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6124 LOGE("failed to add buffering queue");
6128 sinkpad = gst_element_get_static_pad(queue2, "sink");
6129 qsrcpad = gst_element_get_static_pad(queue2, "src");
6131 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6132 LOGE("failed to link [%s:%s]-[%s:%s]",
6133 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6137 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6138 LOGE("failed to sync queue2 state with parent");
6142 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6143 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6147 gst_object_unref(GST_OBJECT(sinkpad));
6151 /* create decodebin */
6152 decodebin = _mmplayer_gst_make_decodebin(player);
6154 LOGE("failed to make decodebin");
6158 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6159 LOGE("failed to add decodebin");
6163 /* to force caps on the decodebin element and avoid reparsing stuff by
6164 * typefind. It also avoids a deadlock in the way typefind activates pads in
6165 * the state change */
6166 g_object_set(decodebin, "sink-caps", caps, NULL);
6168 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6170 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6171 LOGE("failed to link [%s:%s]-[%s:%s]",
6172 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6176 gst_object_unref(GST_OBJECT(sinkpad));
6178 gst_object_unref(GST_OBJECT(qsrcpad));
6181 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6182 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6184 /* set decodebin property about buffer in streaming playback. *
6185 * in case of HLS/DASH, it does not need to have big buffer *
6186 * because it is kind of adaptive streaming. */
6187 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6188 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6189 gint high_percent = 0;
6191 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6192 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6194 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6196 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6198 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6199 "high-percent", high_percent,
6200 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6201 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6202 "max-size-buffers", 0, NULL); // disable or automatic
6205 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6206 LOGE("failed to sync decodebin state with parent");
6217 gst_object_unref(GST_OBJECT(sinkpad));
6220 gst_object_unref(GST_OBJECT(qsrcpad));
6223 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6224 * You need to explicitly set elements to the NULL state before
6225 * dropping the final reference, to allow them to clean up.
6227 gst_element_set_state(queue2, GST_STATE_NULL);
6229 /* And, it still has a parent "player".
6230 * You need to let the parent manage the object instead of unreffing the object directly.
6232 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6233 gst_object_unref(queue2);
6238 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6239 * You need to explicitly set elements to the NULL state before
6240 * dropping the final reference, to allow them to clean up.
6242 gst_element_set_state(decodebin, GST_STATE_NULL);
6244 /* And, it still has a parent "player".
6245 * You need to let the parent manage the object instead of unreffing the object directly.
6248 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6249 gst_object_unref(decodebin);
6257 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6262 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6264 LOGD("class : %s, mime : %s", factory_class, mime);
6266 /* add missing plugin */
6267 /* NOTE : msl should check missing plugin for image mime type.
6268 * Some motion jpeg clips can have playable audio track.
6269 * So, msl have to play audio after displaying popup written video format not supported.
6271 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6272 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6273 LOGD("not found demuxer");
6274 player->not_found_demuxer = TRUE;
6275 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6281 if (!g_strrstr(factory_class, "Demuxer")) {
6282 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6283 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6284 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6286 /* check that clip have multi tracks or not */
6287 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6288 LOGD("video plugin is already linked");
6290 LOGW("add VIDEO to missing plugin");
6291 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6292 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6294 } else if (g_str_has_prefix(mime, "audio")) {
6295 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6296 LOGD("audio plugin is already linked");
6298 LOGW("add AUDIO to missing plugin");
6299 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6300 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6308 return MM_ERROR_NONE;
6312 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6314 mmplayer_t *player = (mmplayer_t *)data;
6318 MMPLAYER_RETURN_IF_FAIL(player);
6320 /* remove fakesink. */
6321 if (!_mmplayer_gst_remove_fakesink(player,
6322 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6323 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6324 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6325 * source element are not same. To overcome this situation, this function will called
6326 * several places and several times. Therefore, this is not an error case.
6331 LOGD("[handle: %p] pipeline has completely constructed", player);
6333 if ((player->ini.async_start) &&
6334 (player->msg_posted == FALSE) &&
6335 (player->cmd >= MMPLAYER_COMMAND_START))
6336 __mmplayer_handle_missed_plugin(player);
6338 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6342 __mmplayer_check_profile(void)
6345 static int profile_tv = -1;
6347 if (__builtin_expect(profile_tv != -1, 1))
6350 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6351 switch (*profileName) {
6366 __mmplayer_get_next_uri(mmplayer_t *player)
6368 mmplayer_parse_profile_t profile;
6370 guint num_of_list = 0;
6373 num_of_list = g_list_length(player->uri_info.uri_list);
6374 uri_idx = player->uri_info.uri_idx;
6376 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6377 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6378 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6380 LOGW("next uri does not exist");
6384 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6385 LOGE("failed to parse profile");
6389 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6390 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6391 LOGW("uri type is not supported(%d)", profile.uri_type);
6395 LOGD("success to find next uri %d", uri_idx);
6399 if (uri_idx == num_of_list) {
6400 LOGE("failed to find next uri");
6404 player->uri_info.uri_idx = uri_idx;
6405 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6407 if (mm_attrs_commit_all(player->attrs)) {
6408 LOGE("failed to commit");
6412 SECURE_LOGD("next playback uri: %s", uri);
6417 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6419 #define REPEAT_COUNT_INFINITE -1
6420 #define REPEAT_COUNT_MIN 2
6421 #define ORIGINAL_URI_ONLY 1
6423 MMHandleType attrs = 0;
6427 guint num_of_uri = 0;
6428 int profile_tv = -1;
6432 LOGD("checking for gapless play option");
6434 if (player->pipeline->textbin) {
6435 LOGE("subtitle path is enabled. gapless play is not supported.");
6439 attrs = MMPLAYER_GET_ATTRS(player);
6441 LOGE("fail to get attributes.");
6445 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6447 /* gapless playback is not supported in case of video at TV profile. */
6448 profile_tv = __mmplayer_check_profile();
6449 if (profile_tv && video) {
6450 LOGW("not support video gapless playback");
6454 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6455 LOGE("failed to get play count");
6457 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6458 LOGE("failed to get gapless mode");
6460 /* check repeat count in case of audio */
6462 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6463 LOGW("gapless is disabled");
6467 num_of_uri = g_list_length(player->uri_info.uri_list);
6469 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6471 if (num_of_uri == ORIGINAL_URI_ONLY) {
6472 /* audio looping path */
6473 if (count >= REPEAT_COUNT_MIN) {
6474 /* decrease play count */
6475 /* we succeeded to rewind. update play count and then wait for next EOS */
6477 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6478 /* commit attribute */
6479 if (mm_attrs_commit_all(attrs))
6480 LOGE("failed to commit attribute");
6482 } else if (count != REPEAT_COUNT_INFINITE) {
6483 LOGD("there is no next uri and no repeat");
6486 LOGD("looping cnt %d", count);
6488 /* gapless playback path */
6489 if (!__mmplayer_get_next_uri(player)) {
6490 LOGE("failed to get next uri");
6497 LOGE("unable to play gapless path. EOS will be posted soon");
6502 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6504 mmplayer_selector_t *selector = &player->selector[type];
6505 mmplayer_gst_element_t *sinkbin = NULL;
6506 main_element_id_e selectorId = MMPLAYER_M_NUM;
6507 main_element_id_e sinkId = MMPLAYER_M_NUM;
6508 GstPad *srcpad = NULL;
6509 GstPad *sinkpad = NULL;
6510 gboolean send_notice = FALSE;
6513 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6515 LOGD("type %d", type);
6518 case MM_PLAYER_TRACK_TYPE_AUDIO:
6519 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6520 sinkId = MMPLAYER_A_BIN;
6521 sinkbin = player->pipeline->audiobin;
6523 case MM_PLAYER_TRACK_TYPE_VIDEO:
6524 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6525 sinkId = MMPLAYER_V_BIN;
6526 sinkbin = player->pipeline->videobin;
6529 case MM_PLAYER_TRACK_TYPE_TEXT:
6530 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6531 sinkId = MMPLAYER_T_BIN;
6532 sinkbin = player->pipeline->textbin;
6535 LOGE("requested type is not supportable");
6540 if (player->pipeline->mainbin[selectorId].gst) {
6543 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6545 if (selector->event_probe_id != 0)
6546 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6547 selector->event_probe_id = 0;
6549 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6550 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6552 if (srcpad && sinkpad) {
6553 /* after getting drained signal there is no data flows, so no need to do pad_block */
6554 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6555 gst_pad_unlink(srcpad, sinkpad);
6557 /* send custom event to sink pad to handle it at video sink */
6559 LOGD("send custom event to sinkpad");
6560 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6561 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6562 gst_pad_send_event(sinkpad, event);
6566 gst_object_unref(sinkpad);
6569 gst_object_unref(srcpad);
6572 LOGD("selector release");
6574 /* release and unref requests pad from the selector */
6575 for (n = 0; n < selector->channels->len; n++) {
6576 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6577 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6579 g_ptr_array_set_size(selector->channels, 0);
6581 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6582 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6584 player->pipeline->mainbin[selectorId].gst = NULL;
6592 __mmplayer_deactivate_old_path(mmplayer_t *player)
6595 MMPLAYER_RETURN_IF_FAIL(player);
6597 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6598 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6599 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6600 LOGE("deactivate selector error");
6604 _mmplayer_track_destroy(player);
6605 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6607 if (player->streamer) {
6608 _mm_player_streaming_initialize(player->streamer, FALSE);
6609 _mm_player_streaming_destroy(player->streamer);
6610 player->streamer = NULL;
6613 MMPLAYER_PLAYBACK_LOCK(player);
6614 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6621 if (!player->msg_posted) {
6622 MMMessageParamType msg = {0,};
6625 msg.code = MM_ERROR_PLAYER_INTERNAL;
6626 LOGE("gapless_uri_play> deactivate error");
6628 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6629 player->msg_posted = TRUE;
6635 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6637 int result = MM_ERROR_NONE;
6638 mmplayer_t *player = (mmplayer_t *)hplayer;
6641 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6643 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6644 if (mm_attrs_commit_all(player->attrs)) {
6645 LOGE("failed to commit the original uri.");
6646 result = MM_ERROR_PLAYER_INTERNAL;
6648 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6649 LOGE("failed to add the original uri in the uri list.");
6657 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6659 mmplayer_t *player = (mmplayer_t *)hplayer;
6660 guint num_of_list = 0;
6664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6665 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6667 if (player->pipeline && player->pipeline->textbin) {
6668 LOGE("subtitle path is enabled.");
6669 return MM_ERROR_PLAYER_INVALID_STATE;
6672 num_of_list = g_list_length(player->uri_info.uri_list);
6674 if (is_first_path) {
6675 if (num_of_list == 0) {
6676 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6677 SECURE_LOGD("add original path : %s", uri);
6679 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6680 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6682 SECURE_LOGD("change original path : %s", uri);
6685 MMHandleType attrs = 0;
6686 attrs = MMPLAYER_GET_ATTRS(player);
6688 if (num_of_list == 0) {
6689 char *original_uri = NULL;
6692 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6694 if (!original_uri) {
6695 LOGE("there is no original uri.");
6696 return MM_ERROR_PLAYER_INVALID_STATE;
6699 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6700 player->uri_info.uri_idx = 0;
6702 SECURE_LOGD("add original path at first : %s", original_uri);
6706 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6707 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6711 return MM_ERROR_NONE;
6715 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6717 mmplayer_t *player = (mmplayer_t *)hplayer;
6718 char *next_uri = NULL;
6719 guint num_of_list = 0;
6722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6724 num_of_list = g_list_length(player->uri_info.uri_list);
6726 if (num_of_list > 0) {
6727 gint uri_idx = player->uri_info.uri_idx;
6729 if (uri_idx < num_of_list-1)
6734 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6735 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6737 *uri = g_strdup(next_uri);
6741 return MM_ERROR_NONE;
6745 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6746 GstCaps *caps, gpointer data)
6748 mmplayer_t *player = (mmplayer_t *)data;
6749 const gchar *klass = NULL;
6750 const gchar *mime = NULL;
6751 gchar *caps_str = NULL;
6753 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6754 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6755 caps_str = gst_caps_to_string(caps);
6757 LOGW("unknown type of caps : %s from %s",
6758 caps_str, GST_ELEMENT_NAME(elem));
6760 MMPLAYER_FREEIF(caps_str);
6762 /* There is no available codec. */
6763 __mmplayer_check_not_supported_codec(player, klass, mime);
6767 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6768 GstCaps *caps, gpointer data)
6770 mmplayer_t *player = (mmplayer_t *)data;
6771 const char *mime = NULL;
6772 gboolean ret = TRUE;
6774 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6775 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6777 if (g_str_has_prefix(mime, "audio")) {
6778 GstStructure *caps_structure = NULL;
6779 gint samplerate = 0;
6781 gchar *caps_str = NULL;
6783 caps_structure = gst_caps_get_structure(caps, 0);
6784 gst_structure_get_int(caps_structure, "rate", &samplerate);
6785 gst_structure_get_int(caps_structure, "channels", &channels);
6787 if ((channels > 0 && samplerate == 0)) {
6788 LOGD("exclude audio...");
6792 caps_str = gst_caps_to_string(caps);
6793 /* set it directly because not sent by TAG */
6794 if (g_strrstr(caps_str, "mobile-xmf"))
6795 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6796 MMPLAYER_FREEIF(caps_str);
6797 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6798 MMMessageParamType msg_param;
6799 memset(&msg_param, 0, sizeof(MMMessageParamType));
6800 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6801 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6802 LOGD("video file is not supported on this device");
6804 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6805 LOGD("already video linked");
6808 LOGD("found new stream");
6815 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6817 gboolean ret = TRUE;
6818 GDBusConnection *conn = NULL;
6820 GVariant *result = NULL;
6821 const gchar *dbus_device_type = NULL;
6822 const gchar *dbus_ret = NULL;
6825 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6827 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6833 result = g_dbus_connection_call_sync(conn,
6834 "org.pulseaudio.Server",
6835 "/org/pulseaudio/StreamManager",
6836 "org.pulseaudio.StreamManager",
6837 "GetCurrentMediaRoutingPath",
6838 g_variant_new("(s)", "out"),
6839 G_VARIANT_TYPE("(ss)"),
6840 G_DBUS_CALL_FLAGS_NONE,
6844 if (!result || err) {
6845 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6851 /* device type is listed in stream-map.json at mmfw-sysconf */
6852 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6854 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6855 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6860 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6861 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6862 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6863 LOGD("audio offload is supportable");
6869 LOGD("audio offload is not supportable");
6873 g_variant_unref(result);
6874 g_object_unref(conn);
6879 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6881 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6882 gint64 position = 0;
6884 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6885 player->pipeline && player->pipeline->mainbin);
6887 MMPLAYER_CMD_LOCK(player);
6888 current_state = MMPLAYER_CURRENT_STATE(player);
6890 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6891 LOGW("getting current position failed in paused");
6893 _mmplayer_unrealize((MMHandleType)player);
6894 _mmplayer_realize((MMHandleType)player);
6896 _mmplayer_set_position((MMHandleType)player, position);
6898 /* async not to be blocked in streaming case */
6899 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6900 if (mm_attrs_commit_all(player->attrs))
6901 LOGE("failed to commit");
6903 _mmplayer_pause((MMHandleType)player);
6905 if (current_state == MM_PLAYER_STATE_PLAYING)
6906 _mmplayer_start((MMHandleType)player);
6907 MMPLAYER_CMD_UNLOCK(player);
6909 LOGD("rebuilding audio pipeline is completed.");
6912 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6914 mmplayer_t *player = (mmplayer_t *)user_data;
6915 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6916 gboolean is_supportable = FALSE;
6918 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6919 LOGW("failed to get device type");
6921 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6923 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6924 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6925 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6926 LOGD("ignore this dev connected info");
6930 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6931 if (player->build_audio_offload == is_supportable) {
6932 LOGD("keep current pipeline without re-building");
6936 /* rebuild pipeline */
6937 LOGD("re-build pipeline - offload: %d", is_supportable);
6938 player->build_audio_offload = FALSE;
6939 __mmplayer_rebuild_audio_pipeline(player);
6945 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6947 unsigned int id = 0;
6949 if (player->audio_device_cb_id != 0) {
6950 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6954 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6955 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6956 LOGD("added device connected cb (%u)", id);
6957 player->audio_device_cb_id = id;
6959 LOGW("failed to add device connected cb");
6967 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6969 gboolean ret = FALSE;
6970 GstElementFactory *factory = NULL;
6973 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6975 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6976 if (!__mmplayer_is_only_mp3_type(player->type))
6979 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6980 LOGD("there is no audio offload sink");
6984 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6985 LOGW("there is no audio device type to support offload");
6989 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6991 LOGW("there is no installed audio offload sink element");
6994 gst_object_unref(factory);
6996 if (!__mmplayer_add_audio_device_connected_cb(player))
6999 if (!__mmplayer_is_audio_offload_device_type(player))
7002 LOGD("audio offload can be built");
7010 static GstAutoplugSelectResult
7011 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7013 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7015 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7016 int audio_offload = 0;
7018 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7019 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7021 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7022 LOGD("expose audio path to build offload output path");
7023 player->build_audio_offload = TRUE;
7024 /* update codec info */
7025 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7026 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7027 player->audiodec_linked = 1;
7029 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7033 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7035 LOGD("audio codec type: %d", codec_type);
7036 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7037 /* sw codec will be skipped */
7038 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7039 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7040 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7045 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7046 /* hw codec will be skipped */
7047 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7048 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7049 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7050 ret = GST_AUTOPLUG_SELECT_SKIP;
7055 /* set stream information */
7056 if (!player->audiodec_linked)
7057 __mmplayer_set_audio_attrs(player, caps);
7059 /* update codec info */
7060 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7061 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7062 player->audiodec_linked = 1;
7064 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7066 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7068 LOGD("video codec type: %d", codec_type);
7069 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7070 /* sw codec is skipped */
7071 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7072 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7073 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7074 ret = GST_AUTOPLUG_SELECT_SKIP;
7078 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7079 /* hw codec is skipped */
7080 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7081 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7082 ret = GST_AUTOPLUG_SELECT_SKIP;
7087 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7088 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7090 /* mark video decoder for acquire */
7091 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7092 LOGW("video decoder resource is already acquired, skip it.");
7093 ret = GST_AUTOPLUG_SELECT_SKIP;
7097 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7098 LOGE("failed to acquire video decoder resource");
7099 ret = GST_AUTOPLUG_SELECT_SKIP;
7102 player->interrupted_by_resource = FALSE;
7105 /* update codec info */
7106 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7107 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7108 player->videodec_linked = 1;
7116 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7117 GstCaps *caps, GstElementFactory *factory, gpointer data)
7119 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7120 mmplayer_t *player = (mmplayer_t *)data;
7122 gchar *factory_name = NULL;
7123 gchar *caps_str = NULL;
7124 const gchar *klass = NULL;
7127 factory_name = GST_OBJECT_NAME(factory);
7128 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7129 caps_str = gst_caps_to_string(caps);
7131 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7133 /* store type string */
7134 if (player->type == NULL) {
7135 player->type = gst_caps_to_string(caps);
7136 __mmplayer_update_content_type_info(player);
7139 /* filtering exclude keyword */
7140 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7141 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7142 LOGW("skipping [%s] by exculde keyword [%s]",
7143 factory_name, player->ini.exclude_element_keyword[idx]);
7145 result = GST_AUTOPLUG_SELECT_SKIP;
7150 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7151 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7152 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7153 factory_name, player->ini.unsupported_codec_keyword[idx]);
7154 result = GST_AUTOPLUG_SELECT_SKIP;
7159 /* exclude webm format */
7160 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7161 * because webm format is not supportable.
7162 * If webm is disabled in "autoplug-continue", there is no state change
7163 * failure or error because the decodebin will expose the pad directly.
7164 * It make MSL invoke _prepare_async_callback.
7165 * So, we need to disable webm format in "autoplug-select" */
7166 if (caps_str && strstr(caps_str, "webm")) {
7167 LOGW("webm is not supported");
7168 result = GST_AUTOPLUG_SELECT_SKIP;
7172 /* check factory class for filtering */
7173 /* NOTE : msl don't need to use image plugins.
7174 * So, those plugins should be skipped for error handling.
7176 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7177 LOGD("skipping [%s] by not required", factory_name);
7178 result = GST_AUTOPLUG_SELECT_SKIP;
7182 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7183 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7184 // TO CHECK : subtitle if needed, add subparse exception.
7185 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7186 result = GST_AUTOPLUG_SELECT_SKIP;
7190 if (g_strrstr(factory_name, "mpegpsdemux")) {
7191 LOGD("skipping PS container - not support");
7192 result = GST_AUTOPLUG_SELECT_SKIP;
7196 if (g_strrstr(factory_name, "mssdemux"))
7197 player->smooth_streaming = TRUE;
7199 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7200 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7203 GstStructure *str = NULL;
7204 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7206 /* don't make video because of not required */
7207 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7208 (!player->set_mode.video_export)) {
7209 LOGD("no need video decoding, expose pad");
7210 result = GST_AUTOPLUG_SELECT_EXPOSE;
7214 /* get w/h for omx state-tune */
7215 /* FIXME: deprecated? */
7216 str = gst_caps_get_structure(caps, 0);
7217 gst_structure_get_int(str, "width", &width);
7220 if (player->v_stream_caps) {
7221 gst_caps_unref(player->v_stream_caps);
7222 player->v_stream_caps = NULL;
7225 player->v_stream_caps = gst_caps_copy(caps);
7226 LOGD("take caps for video state tune");
7227 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7231 if (g_strrstr(klass, "Codec/Decoder")) {
7232 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7233 if (result != GST_AUTOPLUG_SELECT_TRY) {
7234 LOGW("skip add decoder");
7240 MMPLAYER_FREEIF(caps_str);
7246 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7249 //mmplayer_t *player = (mmplayer_t *)data;
7250 GstCaps *caps = NULL;
7252 LOGD("[Decodebin2] pad-removed signal");
7254 caps = gst_pad_query_caps(new_pad, NULL);
7256 LOGW("query caps is NULL");
7260 gchar *caps_str = NULL;
7261 caps_str = gst_caps_to_string(caps);
7263 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7265 MMPLAYER_FREEIF(caps_str);
7266 gst_caps_unref(caps);
7270 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7272 mmplayer_t *player = (mmplayer_t *)data;
7273 GstIterator *iter = NULL;
7274 GValue item = { 0, };
7276 gboolean done = FALSE;
7277 gboolean is_all_drained = TRUE;
7280 MMPLAYER_RETURN_IF_FAIL(player);
7282 LOGD("__mmplayer_gst_decode_drained");
7284 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7285 LOGW("Fail to get cmd lock");
7289 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7290 !__mmplayer_verify_gapless_play_path(player)) {
7291 LOGD("decoding is finished.");
7292 __mmplayer_reset_gapless_state(player);
7293 MMPLAYER_CMD_UNLOCK(player);
7297 player->gapless.reconfigure = TRUE;
7299 /* check decodebin src pads whether they received EOS or not */
7300 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7303 switch (gst_iterator_next(iter, &item)) {
7304 case GST_ITERATOR_OK:
7305 pad = g_value_get_object(&item);
7306 if (pad && !GST_PAD_IS_EOS(pad)) {
7307 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7308 is_all_drained = FALSE;
7311 g_value_reset(&item);
7313 case GST_ITERATOR_RESYNC:
7314 gst_iterator_resync(iter);
7316 case GST_ITERATOR_ERROR:
7317 case GST_ITERATOR_DONE:
7322 g_value_unset(&item);
7323 gst_iterator_free(iter);
7325 if (!is_all_drained) {
7326 LOGD("Wait util the all pads get EOS.");
7327 MMPLAYER_CMD_UNLOCK(player);
7332 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7333 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7335 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7336 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7337 __mmplayer_deactivate_old_path(player);
7338 MMPLAYER_CMD_UNLOCK(player);
7344 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7346 mmplayer_t *player = (mmplayer_t *)data;
7347 const gchar *klass = NULL;
7348 gchar *factory_name = NULL;
7350 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7351 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7353 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7355 if (__mmplayer_add_dump_buffer_probe(player, element))
7356 LOGD("add buffer probe");
7358 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7359 gchar *selected = NULL;
7360 selected = g_strdup(GST_ELEMENT_NAME(element));
7361 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7364 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7365 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7366 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7368 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7369 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7371 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7372 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7373 "max-video-width", player->adaptive_info.limit.width,
7374 "max-video-height", player->adaptive_info.limit.height, NULL);
7376 } else if (g_strrstr(klass, "Demuxer")) {
7377 //LOGD("plugged element is demuxer. take it");
7378 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7379 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7382 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7383 int surface_type = 0;
7385 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7388 // to support trust-zone only
7389 if (g_strrstr(factory_name, "asfdemux")) {
7390 LOGD("set file-location %s", player->profile.uri);
7391 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7392 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7393 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7394 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7395 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7396 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7397 (__mmplayer_is_only_mp3_type(player->type))) {
7398 LOGD("[mpegaudioparse] set streaming pull mode.");
7399 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7401 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7402 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7405 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7406 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7407 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7409 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7410 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7412 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7413 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7414 (MMPLAYER_IS_DASH_STREAMING(player))) {
7415 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7416 _mm_player_streaming_set_multiqueue(player->streamer, element);
7417 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7426 __mmplayer_release_misc(mmplayer_t *player)
7429 bool cur_mode = player->set_mode.rich_audio;
7432 MMPLAYER_RETURN_IF_FAIL(player);
7434 player->video_decoded_cb = NULL;
7435 player->video_decoded_cb_user_param = NULL;
7436 player->video_stream_prerolled = false;
7438 player->audio_decoded_cb = NULL;
7439 player->audio_decoded_cb_user_param = NULL;
7440 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7442 player->video_stream_changed_cb = NULL;
7443 player->video_stream_changed_cb_user_param = NULL;
7445 player->audio_stream_changed_cb = NULL;
7446 player->audio_stream_changed_cb_user_param = NULL;
7448 player->sent_bos = FALSE;
7449 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7451 player->seek_state = MMPLAYER_SEEK_NONE;
7453 player->total_bitrate = 0;
7454 player->total_maximum_bitrate = 0;
7456 player->not_found_demuxer = 0;
7458 player->last_position = 0;
7459 player->duration = 0;
7460 player->http_content_size = 0;
7461 player->not_supported_codec = MISSING_PLUGIN_NONE;
7462 player->can_support_codec = FOUND_PLUGIN_NONE;
7463 player->pending_seek.is_pending = false;
7464 player->pending_seek.pos = 0;
7465 player->msg_posted = FALSE;
7466 player->has_many_types = FALSE;
7467 player->is_subtitle_force_drop = FALSE;
7468 player->play_subtitle = FALSE;
7469 player->adjust_subtitle_pos = 0;
7470 player->has_closed_caption = FALSE;
7471 player->set_mode.video_export = false;
7472 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7473 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7475 player->set_mode.rich_audio = cur_mode;
7477 if (player->audio_device_cb_id > 0 &&
7478 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7479 LOGW("failed to remove audio device_connected_callback");
7480 player->audio_device_cb_id = 0;
7482 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7483 player->bitrate[i] = 0;
7484 player->maximum_bitrate[i] = 0;
7487 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7489 /* remove media stream cb(appsrc cb) */
7490 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7491 player->media_stream_buffer_status_cb[i] = NULL;
7492 player->media_stream_seek_data_cb[i] = NULL;
7493 player->buffer_cb_user_param[i] = NULL;
7494 player->seek_cb_user_param[i] = NULL;
7496 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7498 /* free memory related to audio effect */
7499 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7501 if (player->adaptive_info.var_list) {
7502 g_list_free_full(player->adaptive_info.var_list, g_free);
7503 player->adaptive_info.var_list = NULL;
7506 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7507 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7508 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7510 /* Reset video360 settings to their defaults in case if the pipeline is to be
7513 player->video360_metadata.is_spherical = -1;
7514 player->is_openal_plugin_used = FALSE;
7516 player->is_content_spherical = FALSE;
7517 player->is_video360_enabled = TRUE;
7518 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7519 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7520 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7521 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7522 player->video360_zoom = 1.0f;
7523 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7524 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7526 player->sound.rg_enable = false;
7528 __mmplayer_initialize_video_roi(player);
7533 __mmplayer_release_misc_post(mmplayer_t *player)
7535 char *original_uri = NULL;
7538 /* player->pipeline is already released before. */
7540 MMPLAYER_RETURN_IF_FAIL(player);
7542 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7544 /* clean found audio decoders */
7545 if (player->audio_decoders) {
7546 GList *a_dec = player->audio_decoders;
7547 for (; a_dec; a_dec = g_list_next(a_dec)) {
7548 gchar *name = a_dec->data;
7549 MMPLAYER_FREEIF(name);
7551 g_list_free(player->audio_decoders);
7552 player->audio_decoders = NULL;
7555 /* clean the uri list except original uri */
7556 if (player->uri_info.uri_list) {
7557 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7559 if (player->attrs) {
7560 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7561 LOGD("restore original uri = %s", original_uri);
7563 if (mm_attrs_commit_all(player->attrs))
7564 LOGE("failed to commit the original uri.");
7567 GList *uri_list = player->uri_info.uri_list;
7568 for (; uri_list; uri_list = g_list_next(uri_list)) {
7569 gchar *uri = uri_list->data;
7570 MMPLAYER_FREEIF(uri);
7572 g_list_free(player->uri_info.uri_list);
7573 player->uri_info.uri_list = NULL;
7576 /* clear the audio stream buffer list */
7577 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7579 /* clear the video stream bo list */
7580 __mmplayer_video_stream_destroy_bo_list(player);
7581 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7583 if (player->profile.input_mem.buf) {
7584 free(player->profile.input_mem.buf);
7585 player->profile.input_mem.buf = NULL;
7587 player->profile.input_mem.len = 0;
7588 player->profile.input_mem.offset = 0;
7590 player->uri_info.uri_idx = 0;
7595 __mmplayer_check_subtitle(mmplayer_t *player)
7597 MMHandleType attrs = 0;
7598 char *subtitle_uri = NULL;
7602 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7604 /* get subtitle attribute */
7605 attrs = MMPLAYER_GET_ATTRS(player);
7609 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7610 if (!subtitle_uri || !strlen(subtitle_uri))
7613 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7614 player->is_external_subtitle_present = TRUE;
7622 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7624 MMPLAYER_RETURN_IF_FAIL(player);
7626 if (player->eos_timer) {
7627 LOGD("cancel eos timer");
7628 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7629 player->eos_timer = 0;
7636 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7640 MMPLAYER_RETURN_IF_FAIL(player);
7641 MMPLAYER_RETURN_IF_FAIL(sink);
7643 player->sink_elements = g_list_append(player->sink_elements, sink);
7649 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7653 MMPLAYER_RETURN_IF_FAIL(player);
7654 MMPLAYER_RETURN_IF_FAIL(sink);
7656 player->sink_elements = g_list_remove(player->sink_elements, sink);
7662 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7663 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7665 mmplayer_signal_item_t *item = NULL;
7668 MMPLAYER_RETURN_IF_FAIL(player);
7670 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7671 LOGE("invalid signal type [%d]", type);
7675 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7677 LOGE("cannot connect signal [%s]", signal);
7682 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7683 player->signals[type] = g_list_append(player->signals[type], item);
7689 /* NOTE : be careful with calling this api. please refer to below glib comment
7690 * glib comment : Note that there is a bug in GObject that makes this function much
7691 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7692 * will no longer be called, but, the signal handler is not currently disconnected.
7693 * If the instance is itself being freed at the same time than this doesn't matter,
7694 * since the signal will automatically be removed, but if instance persists,
7695 * then the signal handler will leak. You should not remove the signal yourself
7696 * because in a future versions of GObject, the handler will automatically be
7699 * It's possible to work around this problem in a way that will continue to work
7700 * with future versions of GObject by checking that the signal handler is still
7701 * connected before disconnected it:
7703 * if (g_signal_handler_is_connected(instance, id))
7704 * g_signal_handler_disconnect(instance, id);
7707 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7709 GList *sig_list = NULL;
7710 mmplayer_signal_item_t *item = NULL;
7714 MMPLAYER_RETURN_IF_FAIL(player);
7716 LOGD("release signals type : %d", type);
7718 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7719 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7720 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7721 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7722 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7723 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7727 sig_list = player->signals[type];
7729 for (; sig_list; sig_list = sig_list->next) {
7730 item = sig_list->data;
7732 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7733 if (g_signal_handler_is_connected(item->obj, item->sig))
7734 g_signal_handler_disconnect(item->obj, item->sig);
7737 MMPLAYER_FREEIF(item);
7740 g_list_free(player->signals[type]);
7741 player->signals[type] = NULL;
7749 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7751 mmplayer_t *player = 0;
7752 int prev_display_surface_type = 0;
7753 void *prev_display_overlay = NULL;
7757 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7758 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7760 player = MM_PLAYER_CAST(handle);
7762 /* check video sinkbin is created */
7763 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7764 LOGE("Videosink is already created");
7765 return MM_ERROR_NONE;
7768 LOGD("videosink element is not yet ready");
7770 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7771 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7773 return MM_ERROR_INVALID_ARGUMENT;
7776 /* load previous attributes */
7777 if (player->attrs) {
7778 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7779 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7780 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7781 if (prev_display_surface_type == surface_type) {
7782 LOGD("incoming display surface type is same as previous one, do nothing..");
7784 return MM_ERROR_NONE;
7787 LOGE("failed to load attributes");
7789 return MM_ERROR_PLAYER_INTERNAL;
7792 /* videobin is not created yet, so we just set attributes related to display surface */
7793 LOGD("store display attribute for given surface type(%d)", surface_type);
7794 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7795 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7796 if (mm_attrs_commit_all(player->attrs)) {
7797 LOGE("failed to commit attribute");
7799 return MM_ERROR_PLAYER_INTERNAL;
7803 return MM_ERROR_NONE;
7806 /* Note : if silent is true, then subtitle would not be displayed. :*/
7808 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7810 mmplayer_t *player = (mmplayer_t *)hplayer;
7814 /* check player handle */
7815 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7817 player->set_mode.subtitle_off = silent;
7819 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7823 return MM_ERROR_NONE;
7827 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7829 mmplayer_gst_element_t *mainbin = NULL;
7830 mmplayer_gst_element_t *textbin = NULL;
7831 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7832 GstState current_state = GST_STATE_VOID_PENDING;
7833 GstState element_state = GST_STATE_VOID_PENDING;
7834 GstState element_pending_state = GST_STATE_VOID_PENDING;
7836 GstEvent *event = NULL;
7837 int result = MM_ERROR_NONE;
7839 GstClock *curr_clock = NULL;
7840 GstClockTime base_time, start_time, curr_time;
7845 /* check player handle */
7846 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7848 player->pipeline->mainbin &&
7849 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7851 mainbin = player->pipeline->mainbin;
7852 textbin = player->pipeline->textbin;
7854 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7856 // sync clock with current pipeline
7857 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7858 curr_time = gst_clock_get_time(curr_clock);
7860 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7861 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7863 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7864 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7866 if (current_state > GST_STATE_READY) {
7867 // sync state with current pipeline
7868 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7869 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7870 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7872 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7873 if (GST_STATE_CHANGE_FAILURE == ret) {
7874 LOGE("fail to state change.");
7875 result = MM_ERROR_PLAYER_INTERNAL;
7879 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7880 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7883 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7884 gst_object_unref(curr_clock);
7887 // seek to current position
7888 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7889 result = MM_ERROR_PLAYER_INVALID_STATE;
7890 LOGE("gst_element_query_position failed, invalid state");
7894 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7895 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);
7897 _mmplayer_gst_send_event_to_sink(player, event);
7899 result = MM_ERROR_PLAYER_INTERNAL;
7900 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7904 /* sync state with current pipeline */
7905 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7906 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7907 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7909 return MM_ERROR_NONE;
7912 /* release text pipeline resource */
7913 player->textsink_linked = 0;
7915 /* release signal */
7916 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7918 /* release textbin with it's childs */
7919 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7920 MMPLAYER_FREEIF(player->pipeline->textbin);
7921 player->pipeline->textbin = NULL;
7923 /* release subtitle elem */
7924 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7925 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7931 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7933 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7934 GstState current_state = GST_STATE_VOID_PENDING;
7936 MMHandleType attrs = 0;
7937 mmplayer_gst_element_t *mainbin = NULL;
7938 mmplayer_gst_element_t *textbin = NULL;
7940 gchar *subtitle_uri = NULL;
7941 int result = MM_ERROR_NONE;
7942 const gchar *charset = NULL;
7946 /* check player handle */
7947 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7949 player->pipeline->mainbin &&
7950 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7951 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7953 mainbin = player->pipeline->mainbin;
7954 textbin = player->pipeline->textbin;
7956 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7957 if (current_state < GST_STATE_READY) {
7958 result = MM_ERROR_PLAYER_INVALID_STATE;
7959 LOGE("Pipeline is not in proper state");
7963 attrs = MMPLAYER_GET_ATTRS(player);
7965 LOGE("cannot get content attribute");
7966 result = MM_ERROR_PLAYER_INTERNAL;
7970 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7971 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7972 LOGE("subtitle uri is not proper filepath");
7973 result = MM_ERROR_PLAYER_INVALID_URI;
7977 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7978 LOGE("failed to get storage info of subtitle path");
7979 result = MM_ERROR_PLAYER_INVALID_URI;
7983 LOGD("old subtitle file path is [%s]", subtitle_uri);
7984 LOGD("new subtitle file path is [%s]", filepath);
7986 if (!strcmp(filepath, subtitle_uri)) {
7987 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7990 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7991 if (mm_attrs_commit_all(player->attrs)) {
7992 LOGE("failed to commit.");
7997 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7998 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7999 player->subtitle_language_list = NULL;
8000 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8002 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8003 if (ret != GST_STATE_CHANGE_SUCCESS) {
8004 LOGE("failed to change state of textbin to READY");
8005 result = MM_ERROR_PLAYER_INTERNAL;
8009 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8010 if (ret != GST_STATE_CHANGE_SUCCESS) {
8011 LOGE("failed to change state of subparse to READY");
8012 result = MM_ERROR_PLAYER_INTERNAL;
8016 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8017 if (ret != GST_STATE_CHANGE_SUCCESS) {
8018 LOGE("failed to change state of filesrc to READY");
8019 result = MM_ERROR_PLAYER_INTERNAL;
8023 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8025 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8027 charset = _mmplayer_get_charset(filepath);
8029 LOGD("detected charset is %s", charset);
8030 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8033 result = _mmplayer_sync_subtitle_pipeline(player);
8040 /* API to switch between external subtitles */
8042 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8044 int result = MM_ERROR_NONE;
8045 mmplayer_t *player = (mmplayer_t *)hplayer;
8050 /* check player handle */
8051 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8053 /* filepath can be null in idle state */
8055 /* check file path */
8056 if ((path = strstr(filepath, "file://")))
8057 result = _mmplayer_exist_file_path(path + 7);
8059 result = _mmplayer_exist_file_path(filepath);
8061 if (result != MM_ERROR_NONE) {
8062 LOGE("invalid subtitle path 0x%X", result);
8063 return result; /* file not found or permission denied */
8067 if (!player->pipeline) {
8069 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8070 if (mm_attrs_commit_all(player->attrs)) {
8071 LOGE("failed to commit"); /* subtitle path will not be created */
8072 return MM_ERROR_PLAYER_INTERNAL;
8075 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8076 /* check filepath */
8077 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8079 if (!__mmplayer_check_subtitle(player)) {
8080 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8081 if (mm_attrs_commit_all(player->attrs)) {
8082 LOGE("failed to commit");
8083 return MM_ERROR_PLAYER_INTERNAL;
8086 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8087 LOGE("fail to create text pipeline");
8088 return MM_ERROR_PLAYER_INTERNAL;
8091 result = _mmplayer_sync_subtitle_pipeline(player);
8093 result = __mmplayer_change_external_subtitle_language(player, filepath);
8096 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8097 player->is_external_subtitle_added_now = TRUE;
8099 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8100 if (!player->subtitle_language_list) {
8101 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8102 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8103 LOGW("subtitle language list is not updated yet");
8105 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8113 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8115 int result = MM_ERROR_NONE;
8116 gchar *change_pad_name = NULL;
8117 GstPad *sinkpad = NULL;
8118 mmplayer_gst_element_t *mainbin = NULL;
8119 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8120 GstCaps *caps = NULL;
8121 gint total_track_num = 0;
8125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8126 MM_ERROR_PLAYER_NOT_INITIALIZED);
8128 LOGD("Change Track(%d) to %d", type, index);
8130 mainbin = player->pipeline->mainbin;
8132 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8133 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8134 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8135 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8137 /* Changing Video Track is not supported. */
8138 LOGE("Track Type Error");
8142 if (mainbin[elem_idx].gst == NULL) {
8143 result = MM_ERROR_PLAYER_NO_OP;
8144 LOGD("Req track doesn't exist");
8148 total_track_num = player->selector[type].total_track_num;
8149 if (total_track_num <= 0) {
8150 result = MM_ERROR_PLAYER_NO_OP;
8151 LOGD("Language list is not available");
8155 if ((index < 0) || (index >= total_track_num)) {
8156 result = MM_ERROR_INVALID_ARGUMENT;
8157 LOGD("Not a proper index : %d", index);
8161 /*To get the new pad from the selector*/
8162 change_pad_name = g_strdup_printf("sink_%u", index);
8163 if (change_pad_name == NULL) {
8164 result = MM_ERROR_PLAYER_INTERNAL;
8165 LOGD("Pad does not exists");
8169 LOGD("new active pad name: %s", change_pad_name);
8171 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8172 if (sinkpad == NULL) {
8173 LOGD("sinkpad is NULL");
8174 result = MM_ERROR_PLAYER_INTERNAL;
8178 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8179 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8181 caps = gst_pad_get_current_caps(sinkpad);
8182 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8185 gst_object_unref(sinkpad);
8187 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8188 __mmplayer_set_audio_attrs(player, caps);
8191 MMPLAYER_FREEIF(change_pad_name);
8196 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8198 int result = MM_ERROR_NONE;
8199 mmplayer_t *player = NULL;
8200 mmplayer_gst_element_t *mainbin = NULL;
8202 gint current_active_index = 0;
8204 GstState current_state = GST_STATE_VOID_PENDING;
8205 GstEvent *event = NULL;
8210 player = (mmplayer_t *)hplayer;
8211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8213 if (!player->pipeline) {
8214 LOGE("Track %d pre setting -> %d", type, index);
8216 player->selector[type].active_pad_index = index;
8220 mainbin = player->pipeline->mainbin;
8222 current_active_index = player->selector[type].active_pad_index;
8224 /*If index is same as running index no need to change the pad*/
8225 if (current_active_index == index)
8228 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8229 result = MM_ERROR_PLAYER_INVALID_STATE;
8233 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8234 if (current_state < GST_STATE_PAUSED) {
8235 result = MM_ERROR_PLAYER_INVALID_STATE;
8236 LOGW("Pipeline not in porper state");
8240 result = __mmplayer_change_selector_pad(player, type, index);
8241 if (result != MM_ERROR_NONE) {
8242 LOGE("change selector pad error");
8246 player->selector[type].active_pad_index = index;
8248 if (current_state == GST_STATE_PLAYING) {
8249 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8250 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8251 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8253 _mmplayer_gst_send_event_to_sink(player, event);
8255 result = MM_ERROR_PLAYER_INTERNAL;
8265 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8267 mmplayer_t *player = (mmplayer_t *)hplayer;
8271 /* check player handle */
8272 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8274 *silent = player->set_mode.subtitle_off;
8276 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8280 return MM_ERROR_NONE;
8284 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8286 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8287 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8289 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8290 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8294 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8295 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8296 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8297 mmplayer_dump_t *dump_s;
8298 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8299 if (dump_s == NULL) {
8300 LOGE("malloc fail");
8304 dump_s->dump_element_file = NULL;
8305 dump_s->dump_pad = NULL;
8306 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8308 if (dump_s->dump_pad) {
8309 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8310 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]);
8311 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8312 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);
8313 /* add list for removed buffer probe and close FILE */
8314 player->dump_list = g_list_append(player->dump_list, dump_s);
8315 LOGD("%s sink pad added buffer probe for dump", factory_name);
8318 MMPLAYER_FREEIF(dump_s);
8319 LOGE("failed to get %s sink pad added", factory_name);
8326 static GstPadProbeReturn
8327 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8329 FILE *dump_data = (FILE *)u_data;
8331 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8332 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8334 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8336 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8338 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8340 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8342 gst_buffer_unmap(buffer, &probe_info);
8344 return GST_PAD_PROBE_OK;
8348 __mmplayer_release_dump_list(GList *dump_list)
8350 GList *d_list = dump_list;
8355 for (; d_list; d_list = g_list_next(d_list)) {
8356 mmplayer_dump_t *dump_s = d_list->data;
8357 if (dump_s->dump_pad) {
8358 if (dump_s->probe_handle_id)
8359 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8360 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8362 if (dump_s->dump_element_file) {
8363 fclose(dump_s->dump_element_file);
8364 dump_s->dump_element_file = NULL;
8366 MMPLAYER_FREEIF(dump_s);
8368 g_list_free(dump_list);
8373 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8375 mmplayer_t *player = (mmplayer_t *)hplayer;
8379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8380 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8382 *exist = (bool)player->has_closed_caption;
8386 return MM_ERROR_NONE;
8390 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8394 // LOGD("unref internal gst buffer %p", buffer);
8395 gst_buffer_unref((GstBuffer *)buffer);
8402 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8404 mmplayer_t *player = (mmplayer_t *)hplayer;
8408 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8409 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8411 if (MMPLAYER_IS_STREAMING(player))
8412 *timeout = (int)player->ini.live_state_change_timeout;
8414 *timeout = (int)player->ini.localplayback_state_change_timeout;
8416 LOGD("timeout = %d", *timeout);
8419 return MM_ERROR_NONE;
8423 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8425 mmplayer_t *player = (mmplayer_t *)hplayer;
8429 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8430 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8432 *num = player->video_num_buffers;
8433 *extra_num = player->video_extra_num_buffers;
8435 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8438 return MM_ERROR_NONE;
8442 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8446 MMPLAYER_RETURN_IF_FAIL(player);
8448 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8450 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8451 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8452 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8453 player->storage_info[i].id = -1;
8454 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8456 if (path_type != MMPLAYER_PATH_MAX)
8465 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8467 int ret = MM_ERROR_NONE;
8468 mmplayer_t *player = (mmplayer_t *)hplayer;
8469 MMMessageParamType msg_param = {0, };
8472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 LOGW("state changed storage %d:%d", id, state);
8476 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8477 return MM_ERROR_NONE;
8479 /* FIXME: text path should be handled seperately. */
8480 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8481 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8482 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8483 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8484 LOGW("external storage is removed");
8486 if (player->msg_posted == FALSE) {
8487 memset(&msg_param, 0, sizeof(MMMessageParamType));
8488 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8489 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8490 player->msg_posted = TRUE;
8493 /* unrealize the player */
8494 ret = _mmplayer_unrealize(hplayer);
8495 if (ret != MM_ERROR_NONE)
8496 LOGE("failed to unrealize");
8504 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8506 int ret = MM_ERROR_NONE;
8507 mmplayer_t *player = (mmplayer_t *)hplayer;
8508 int idx = 0, total = 0;
8509 gchar *result = NULL, *tmp = NULL;
8512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8513 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8515 total = *num = g_list_length(player->adaptive_info.var_list);
8517 LOGW("There is no stream variant info.");
8521 result = g_strdup("");
8522 for (idx = 0 ; idx < total ; idx++) {
8523 stream_variant_t *v_data = NULL;
8524 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8527 gchar data[64] = {0};
8528 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8530 tmp = g_strconcat(result, data, NULL);
8534 LOGW("There is no variant data in %d", idx);
8539 *var_info = (char *)result;
8541 LOGD("variant info %d:%s", *num, *var_info);
8547 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8549 int ret = MM_ERROR_NONE;
8550 mmplayer_t *player = (mmplayer_t *)hplayer;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8557 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8558 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8559 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8561 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8562 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8563 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8564 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8566 /* FIXME: seek to current position for applying new variant limitation */
8575 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8577 int ret = MM_ERROR_NONE;
8578 mmplayer_t *player = (mmplayer_t *)hplayer;
8581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8584 *bandwidth = player->adaptive_info.limit.bandwidth;
8585 *width = player->adaptive_info.limit.width;
8586 *height = player->adaptive_info.limit.height;
8588 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8595 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8597 int ret = MM_ERROR_NONE;
8598 mmplayer_t *player = (mmplayer_t *)hplayer;
8601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8602 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8603 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8605 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8607 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8608 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8609 else /* live case */
8610 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8612 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8619 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8621 #define IDX_FIRST_SW_CODEC 0
8622 mmplayer_t *player = (mmplayer_t *)hplayer;
8623 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8624 MMHandleType attrs = 0;
8627 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8629 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8630 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8631 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8633 switch (stream_type) {
8634 case MM_PLAYER_STREAM_TYPE_AUDIO:
8635 /* to support audio codec selection, codec info have to be added in ini file as below.
8636 audio codec element hw = xxxx
8637 audio codec element sw = avdec */
8638 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8639 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8640 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8641 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8642 LOGE("There is no audio codec info for codec_type %d", codec_type);
8643 return MM_ERROR_PLAYER_NO_OP;
8646 case MM_PLAYER_STREAM_TYPE_VIDEO:
8647 /* to support video codec selection, codec info have to be added in ini file as below.
8648 video codec element hw = omx
8649 video codec element sw = avdec */
8650 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8651 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8652 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8653 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8654 LOGE("There is no video codec info for codec_type %d", codec_type);
8655 return MM_ERROR_PLAYER_NO_OP;
8659 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8660 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8664 LOGD("update %s codec_type to %d", attr_name, codec_type);
8666 attrs = MMPLAYER_GET_ATTRS(player);
8667 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8669 if (mm_attrs_commit_all(player->attrs)) {
8670 LOGE("failed to commit codec_type attributes");
8671 return MM_ERROR_PLAYER_INTERNAL;
8675 return MM_ERROR_NONE;
8679 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8681 mmplayer_t *player = (mmplayer_t *)hplayer;
8682 GstElement *rg_vol_element = NULL;
8686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8688 player->sound.rg_enable = enabled;
8690 /* just hold rgvolume enable value if pipeline is not ready */
8691 if (!player->pipeline || !player->pipeline->audiobin) {
8692 LOGD("pipeline is not ready. holding rgvolume enable value");
8693 return MM_ERROR_NONE;
8696 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8698 if (!rg_vol_element) {
8699 LOGD("rgvolume element is not created");
8700 return MM_ERROR_PLAYER_INTERNAL;
8704 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8706 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8710 return MM_ERROR_NONE;
8714 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8716 mmplayer_t *player = (mmplayer_t *)hplayer;
8717 GstElement *rg_vol_element = NULL;
8718 gboolean enable = FALSE;
8722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8723 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8725 /* just hold enable_rg value if pipeline is not ready */
8726 if (!player->pipeline || !player->pipeline->audiobin) {
8727 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8728 *enabled = player->sound.rg_enable;
8729 return MM_ERROR_NONE;
8732 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8734 if (!rg_vol_element) {
8735 LOGD("rgvolume element is not created");
8736 return MM_ERROR_PLAYER_INTERNAL;
8739 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8740 *enabled = (bool)enable;
8744 return MM_ERROR_NONE;
8748 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8750 mmplayer_t *player = (mmplayer_t *)hplayer;
8751 MMHandleType attrs = 0;
8752 void *handle = NULL;
8753 int ret = MM_ERROR_NONE;
8757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8759 attrs = MMPLAYER_GET_ATTRS(player);
8760 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8762 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8764 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8765 return MM_ERROR_PLAYER_INTERNAL;
8768 player->video_roi.scale_x = scale_x;
8769 player->video_roi.scale_y = scale_y;
8770 player->video_roi.scale_width = scale_width;
8771 player->video_roi.scale_height = scale_height;
8773 /* check video sinkbin is created */
8774 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8775 return MM_ERROR_NONE;
8777 if (!gst_video_overlay_set_video_roi_area(
8778 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8779 scale_x, scale_y, scale_width, scale_height))
8780 ret = MM_ERROR_PLAYER_INTERNAL;
8782 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8783 scale_x, scale_y, scale_width, scale_height);
8791 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8793 mmplayer_t *player = (mmplayer_t *)hplayer;
8794 int ret = MM_ERROR_NONE;
8798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8799 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8801 *scale_x = player->video_roi.scale_x;
8802 *scale_y = player->video_roi.scale_y;
8803 *scale_width = player->video_roi.scale_width;
8804 *scale_height = player->video_roi.scale_height;
8806 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8807 *scale_x, *scale_y, *scale_width, *scale_height);
8813 __mmplayer_update_duration_value(mmplayer_t *player)
8815 gboolean ret = FALSE;
8816 gint64 dur_nsec = 0;
8817 LOGD("try to update duration");
8819 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8820 player->duration = dur_nsec;
8821 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8825 if (player->duration < 0) {
8826 LOGW("duration is Non-Initialized !!!");
8827 player->duration = 0;
8830 /* update streaming service type */
8831 player->streaming_type = _mmplayer_get_stream_service_type(player);
8833 /* check duration is OK */
8834 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8835 /* FIXIT : find another way to get duration here. */
8836 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8842 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8844 /* update audio params
8845 NOTE : We need original audio params and it can be only obtained from src pad of audio
8846 decoder. Below code only valid when we are not using 'resampler' just before
8847 'audioconverter'. */
8848 GstCaps *caps_a = NULL;
8850 gint samplerate = 0, channels = 0;
8851 GstStructure *p = NULL;
8852 GstElement *aconv = NULL;
8854 LOGD("try to update audio attrs");
8856 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8858 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8859 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8860 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8861 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8863 LOGE("there is no audio converter");
8867 pad = gst_element_get_static_pad(aconv, "sink");
8870 LOGW("failed to get pad from audio converter");
8874 caps_a = gst_pad_get_current_caps(pad);
8876 LOGW("not ready to get audio caps");
8877 gst_object_unref(pad);
8881 p = gst_caps_get_structure(caps_a, 0);
8883 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8885 gst_structure_get_int(p, "rate", &samplerate);
8886 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8888 gst_structure_get_int(p, "channels", &channels);
8889 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8891 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8893 gst_caps_unref(caps_a);
8894 gst_object_unref(pad);
8900 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8902 LOGD("try to update video attrs");
8904 GstCaps *caps_v = NULL;
8908 GstStructure *p = NULL;
8910 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8911 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8913 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8915 LOGD("no videosink sink pad");
8919 caps_v = gst_pad_get_current_caps(pad);
8920 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8921 if (!caps_v && player->v_stream_caps) {
8922 caps_v = player->v_stream_caps;
8923 gst_caps_ref(caps_v);
8927 LOGD("no negitiated caps from videosink");
8928 gst_object_unref(pad);
8932 p = gst_caps_get_structure(caps_v, 0);
8933 gst_structure_get_int(p, "width", &width);
8934 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8936 gst_structure_get_int(p, "height", &height);
8937 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8939 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8941 SECURE_LOGD("width : %d height : %d", width, height);
8943 gst_caps_unref(caps_v);
8944 gst_object_unref(pad);
8947 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8948 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8955 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8957 gboolean ret = FALSE;
8958 guint64 data_size = 0;
8962 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8963 if (!player->duration)
8966 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8967 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8968 if (stat(path, &sb) == 0)
8969 data_size = (guint64)sb.st_size;
8971 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8972 data_size = player->http_content_size;
8975 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8978 guint64 bitrate = 0;
8979 guint64 msec_dur = 0;
8981 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8983 bitrate = data_size * 8 * 1000 / msec_dur;
8984 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8985 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8989 LOGD("player duration is less than 0");
8993 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8994 if (player->total_bitrate) {
8995 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9004 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9006 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9007 data->uri_type = uri_type;
9011 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9013 int ret = MM_ERROR_PLAYER_INVALID_URI;
9015 char *buffer = NULL;
9016 char *seperator = strchr(path, ',');
9017 char ext[100] = {0,}, size[100] = {0,};
9020 if ((buffer = strstr(path, "ext="))) {
9021 buffer += strlen("ext=");
9023 if (strlen(buffer)) {
9024 strncpy(ext, buffer, 99);
9026 if ((seperator = strchr(ext, ','))
9027 || (seperator = strchr(ext, ' '))
9028 || (seperator = strchr(ext, '\0'))) {
9029 seperator[0] = '\0';
9034 if ((buffer = strstr(path, "size="))) {
9035 buffer += strlen("size=");
9037 if (strlen(buffer) > 0) {
9038 strncpy(size, buffer, 99);
9040 if ((seperator = strchr(size, ','))
9041 || (seperator = strchr(size, ' '))
9042 || (seperator = strchr(size, '\0'))) {
9043 seperator[0] = '\0';
9046 mem_size = atoi(size);
9051 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9053 if (mem_size && param) {
9054 if (data->input_mem.buf)
9055 free(data->input_mem.buf);
9056 data->input_mem.buf = malloc(mem_size);
9058 if (data->input_mem.buf) {
9059 memcpy(data->input_mem.buf, param, mem_size);
9060 data->input_mem.len = mem_size;
9061 ret = MM_ERROR_NONE;
9063 LOGE("failed to alloc mem %d", mem_size);
9064 ret = MM_ERROR_PLAYER_INTERNAL;
9067 data->input_mem.offset = 0;
9068 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9075 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9077 gchar *location = NULL;
9080 int ret = MM_ERROR_NONE;
9082 if ((path = strstr(uri, "file://"))) {
9083 location = g_filename_from_uri(uri, NULL, &err);
9084 if (!location || (err != NULL)) {
9085 LOGE("Invalid URI '%s' for filesrc: %s", path,
9086 (err != NULL) ? err->message : "unknown error");
9090 MMPLAYER_FREEIF(location);
9092 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9093 return MM_ERROR_PLAYER_INVALID_URI;
9095 LOGD("path from uri: %s", location);
9098 path = (location != NULL) ? (location) : ((char *)uri);
9101 ret = _mmplayer_exist_file_path(path);
9103 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9104 if (ret == MM_ERROR_NONE) {
9105 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9106 if (_mmplayer_is_sdp_file(path)) {
9107 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9108 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9110 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9112 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9113 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9115 LOGE("invalid uri, could not play..");
9116 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9119 MMPLAYER_FREEIF(location);
9124 static mmplayer_video_decoded_data_info_t *
9125 __mmplayer_create_stream_from_pad(GstPad *pad)
9127 GstCaps *caps = NULL;
9128 GstStructure *structure = NULL;
9129 unsigned int fourcc = 0;
9130 const gchar *string_format = NULL;
9131 mmplayer_video_decoded_data_info_t *stream = NULL;
9133 MMPixelFormatType format;
9136 caps = gst_pad_get_current_caps(pad);
9138 LOGE("Caps is NULL.");
9142 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9143 structure = gst_caps_get_structure(caps, 0);
9144 gst_structure_get_int(structure, "width", &width);
9145 gst_structure_get_int(structure, "height", &height);
9146 string_format = gst_structure_get_string(structure, "format");
9149 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9150 format = _mmplayer_get_pixtype(fourcc);
9151 gst_video_info_from_caps(&info, caps);
9152 gst_caps_unref(caps);
9155 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9156 LOGE("Wrong condition!!");
9160 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9162 LOGE("failed to alloc mem for video data");
9166 stream->width = width;
9167 stream->height = height;
9168 stream->format = format;
9169 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9175 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9177 unsigned int pitch = 0;
9178 unsigned int size = 0;
9180 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9183 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9184 bo = gst_tizen_memory_get_bos(mem, index);
9186 stream->bo[index] = tbm_bo_ref(bo);
9188 LOGE("failed to get bo for index %d", index);
9191 for (index = 0; index < stream->plane_num; index++) {
9192 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9193 stream->stride[index] = pitch;
9195 stream->elevation[index] = size / pitch;
9197 stream->elevation[index] = stream->height;
9202 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9204 if (stream->format == MM_PIXEL_FORMAT_I420) {
9205 int ret = TBM_SURFACE_ERROR_NONE;
9206 tbm_surface_h surface;
9207 tbm_surface_info_s info;
9209 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9211 ret = tbm_surface_get_info(surface, &info);
9212 if (ret != TBM_SURFACE_ERROR_NONE) {
9213 tbm_surface_destroy(surface);
9217 tbm_surface_destroy(surface);
9218 stream->stride[0] = info.planes[0].stride;
9219 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9220 stream->stride[1] = info.planes[1].stride;
9221 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9222 stream->stride[2] = info.planes[2].stride;
9223 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9224 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9225 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9226 stream->stride[0] = stream->width * 4;
9227 stream->elevation[0] = stream->height;
9228 stream->bo_size = stream->stride[0] * stream->height;
9230 LOGE("Not support format %d", stream->format);
9238 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9240 tbm_bo_handle thandle;
9242 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9243 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9244 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9248 unsigned char *src = NULL;
9249 unsigned char *dest = NULL;
9250 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9252 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9254 LOGE("fail to gst_memory_map");
9258 if (!mapinfo.data) {
9259 LOGE("data pointer is wrong");
9263 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9264 if (!stream->bo[0]) {
9265 LOGE("Fail to tbm_bo_alloc!!");
9269 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9271 LOGE("thandle pointer is wrong");
9275 if (stream->format == MM_PIXEL_FORMAT_I420) {
9276 src_stride[0] = GST_ROUND_UP_4(stream->width);
9277 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9278 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9279 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9282 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9283 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9285 for (i = 0; i < 3; i++) {
9286 src = mapinfo.data + src_offset[i];
9287 dest = thandle.ptr + dest_offset[i];
9292 for (j = 0; j < stream->height >> k; j++) {
9293 memcpy(dest, src, stream->width>>k);
9294 src += src_stride[i];
9295 dest += stream->stride[i];
9298 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9299 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9301 LOGE("Not support format %d", stream->format);
9305 tbm_bo_unmap(stream->bo[0]);
9306 gst_memory_unmap(mem, &mapinfo);
9312 tbm_bo_unmap(stream->bo[0]);
9315 gst_memory_unmap(mem, &mapinfo);
9321 __mmplayer_set_pause_state(mmplayer_t *player)
9323 if (player->sent_bos)
9326 /* rtsp case, get content attrs by GstMessage */
9327 if (MMPLAYER_IS_RTSP_STREAMING(player))
9330 /* it's first time to update all content attrs. */
9331 _mmplayer_update_content_attrs(player, ATTR_ALL);
9335 __mmplayer_set_playing_state(mmplayer_t *player)
9337 gchar *audio_codec = NULL;
9339 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9340 /* initialize because auto resume is done well. */
9341 player->resumed_by_rewind = FALSE;
9342 player->playback_rate = 1.0;
9345 if (player->sent_bos)
9348 /* try to get content metadata */
9350 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9351 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9352 * legacy mmfw-player api
9354 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9356 if ((player->cmd == MMPLAYER_COMMAND_START)
9357 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9358 __mmplayer_handle_missed_plugin(player);
9361 /* check audio codec field is set or not
9362 * we can get it from typefinder or codec's caps.
9364 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9366 /* The codec format can't be sent for audio only case like amr, mid etc.
9367 * Because, parser don't make related TAG.
9368 * So, if it's not set yet, fill it with found data.
9371 if (g_strrstr(player->type, "audio/midi"))
9372 audio_codec = "MIDI";
9373 else if (g_strrstr(player->type, "audio/x-amr"))
9374 audio_codec = "AMR";
9375 else if (g_strrstr(player->type, "audio/mpeg")
9376 && !g_strrstr(player->type, "mpegversion=(int)1"))
9377 audio_codec = "AAC";
9379 audio_codec = "unknown";
9381 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9383 if (mm_attrs_commit_all(player->attrs))
9384 LOGE("failed to update attributes");
9386 LOGD("set audio codec type with caps");