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
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
278 if (mm_attrs_commit_all(attrs)) {
279 LOGE("failed to update attributes");
289 _mmplayer_get_stream_service_type(mmplayer_t *player)
291 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
297 player->pipeline->mainbin &&
298 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
299 STREAMING_SERVICE_NONE);
301 /* streaming service type if streaming */
302 if (!MMPLAYER_IS_STREAMING(player))
303 return STREAMING_SERVICE_NONE;
305 streaming_type = (player->duration == 0) ?
306 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
308 switch (streaming_type) {
309 case STREAMING_SERVICE_LIVE:
310 LOGD("it's live streaming");
312 case STREAMING_SERVICE_VOD:
313 LOGD("it's vod streaming");
316 LOGE("should not get here");
322 return streaming_type;
325 /* this function sets the player state and also report
326 * it to applicaton by calling callback function
329 _mmplayer_set_state(mmplayer_t *player, int state)
331 MMMessageParamType msg = {0, };
333 MMPLAYER_RETURN_IF_FAIL(player);
335 if (MMPLAYER_CURRENT_STATE(player) == state) {
336 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
337 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
341 /* update player states */
342 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
343 MMPLAYER_CURRENT_STATE(player) = state;
345 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
346 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
349 MMPLAYER_PRINT_STATE(player);
351 switch (MMPLAYER_CURRENT_STATE(player)) {
352 case MM_PLAYER_STATE_NULL:
353 case MM_PLAYER_STATE_READY:
355 case MM_PLAYER_STATE_PAUSED:
356 __mmplayer_set_pause_state(player);
358 case MM_PLAYER_STATE_PLAYING:
359 __mmplayer_set_playing_state(player);
361 case MM_PLAYER_STATE_NONE:
363 LOGW("invalid target state, there is nothing to do.");
368 /* post message to application */
369 if (MMPLAYER_TARGET_STATE(player) == state) {
370 /* fill the message with state of player */
371 msg.union_type = MM_MSG_UNION_STATE;
372 msg.state.previous = MMPLAYER_PREV_STATE(player);
373 msg.state.current = MMPLAYER_CURRENT_STATE(player);
375 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
377 /* state changed by resource callback */
378 if (player->interrupted_by_resource)
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
380 else /* state changed by usecase */
381 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
384 LOGD("intermediate state, do nothing.");
385 MMPLAYER_PRINT_STATE(player);
389 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
390 && !player->sent_bos) {
391 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
392 player->sent_bos = TRUE;
399 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
401 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
402 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
404 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
406 LOGD("incomming command : %d ", command);
408 current_state = MMPLAYER_CURRENT_STATE(player);
409 pending_state = MMPLAYER_PENDING_STATE(player);
411 MMPLAYER_PRINT_STATE(player);
414 case MMPLAYER_COMMAND_CREATE:
416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
418 if (current_state == MM_PLAYER_STATE_NULL ||
419 current_state == MM_PLAYER_STATE_READY ||
420 current_state == MM_PLAYER_STATE_PAUSED ||
421 current_state == MM_PLAYER_STATE_PLAYING)
426 case MMPLAYER_COMMAND_DESTROY:
428 /* destroy can called anytime */
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
434 case MMPLAYER_COMMAND_REALIZE:
436 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
438 if (pending_state != MM_PLAYER_STATE_NONE) {
441 /* need ready state to realize */
442 if (current_state == MM_PLAYER_STATE_READY)
445 if (current_state != MM_PLAYER_STATE_NULL)
451 case MMPLAYER_COMMAND_UNREALIZE:
453 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
455 if (current_state == MM_PLAYER_STATE_NULL)
460 case MMPLAYER_COMMAND_START:
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
464 if (pending_state == MM_PLAYER_STATE_NONE) {
465 if (current_state == MM_PLAYER_STATE_PLAYING)
467 else if (current_state != MM_PLAYER_STATE_READY &&
468 current_state != MM_PLAYER_STATE_PAUSED)
470 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
472 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
473 LOGD("player is going to paused state, just change the pending state as playing");
480 case MMPLAYER_COMMAND_STOP:
482 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
484 if (current_state == MM_PLAYER_STATE_READY)
487 /* need playing/paused state to stop */
488 if (current_state != MM_PLAYER_STATE_PLAYING &&
489 current_state != MM_PLAYER_STATE_PAUSED)
494 case MMPLAYER_COMMAND_PAUSE:
496 if (MMPLAYER_IS_LIVE_STREAMING(player))
499 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
500 goto NOT_COMPLETED_SEEK;
502 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
504 if (pending_state == MM_PLAYER_STATE_NONE) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
507 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
509 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
511 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
512 if (current_state == MM_PLAYER_STATE_PAUSED)
513 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
520 case MMPLAYER_COMMAND_RESUME:
522 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
523 goto NOT_COMPLETED_SEEK;
525 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
527 if (pending_state == MM_PLAYER_STATE_NONE) {
528 if (current_state == MM_PLAYER_STATE_PLAYING)
530 else if (current_state != MM_PLAYER_STATE_PAUSED)
532 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
534 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
535 LOGD("player is going to paused state, just change the pending state as playing");
545 player->cmd = command;
547 return MM_ERROR_NONE;
550 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
551 MMPLAYER_STATE_GET_NAME(current_state), command);
552 return MM_ERROR_PLAYER_INVALID_STATE;
555 LOGW("not completed seek");
556 return MM_ERROR_PLAYER_DOING_SEEK;
559 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
560 return MM_ERROR_PLAYER_NO_OP;
563 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
564 return MM_ERROR_PLAYER_NO_OP;
567 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
569 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
570 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
573 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
576 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
577 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
579 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
580 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
583 LOGE("invalid mmplayer resource type %d", type);
584 return MM_ERROR_PLAYER_INTERNAL;
587 if (player->hw_resource[type] != NULL) {
588 LOGD("[%d type] resource was already acquired", type);
589 return MM_ERROR_NONE;
592 LOGD("mark for acquire [%d type] resource", type);
593 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
594 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
600 rm_ret = mm_resource_manager_commit(player->resource_manager);
601 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
602 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
603 return MM_ERROR_PLAYER_INTERNAL;
607 return MM_ERROR_NONE;
610 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
612 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
616 if (player->hw_resource[type] == NULL) {
617 LOGD("there is no acquired [%d type] resource", type);
618 return MM_ERROR_NONE;
621 LOGD("mark for release [%d type] resource", type);
622 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
623 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
624 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
625 return MM_ERROR_PLAYER_INTERNAL;
628 player->hw_resource[type] = NULL;
630 rm_ret = mm_resource_manager_commit(player->resource_manager);
631 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633 return MM_ERROR_PLAYER_INTERNAL;
637 return MM_ERROR_NONE;
641 __mmplayer_initialize_gapless_play(mmplayer_t *player)
647 player->smooth_streaming = FALSE;
648 player->videodec_linked = 0;
649 player->audiodec_linked = 0;
650 player->textsink_linked = 0;
651 player->is_external_subtitle_present = FALSE;
652 player->is_external_subtitle_added_now = FALSE;
653 player->not_supported_codec = MISSING_PLUGIN_NONE;
654 player->can_support_codec = FOUND_PLUGIN_NONE;
655 player->pending_seek.is_pending = false;
656 player->pending_seek.pos = 0;
657 player->msg_posted = FALSE;
658 player->has_many_types = FALSE;
659 player->no_more_pad = FALSE;
660 player->not_found_demuxer = 0;
661 player->seek_state = MMPLAYER_SEEK_NONE;
662 player->is_subtitle_force_drop = FALSE;
663 player->play_subtitle = FALSE;
664 player->adjust_subtitle_pos = 0;
666 player->total_bitrate = 0;
667 player->total_maximum_bitrate = 0;
669 _mmplayer_track_initialize(player);
670 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
672 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
673 player->bitrate[i] = 0;
674 player->maximum_bitrate[i] = 0;
677 if (player->v_stream_caps) {
678 gst_caps_unref(player->v_stream_caps);
679 player->v_stream_caps = NULL;
682 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
684 /* clean found audio decoders */
685 if (player->audio_decoders) {
686 GList *a_dec = player->audio_decoders;
687 for (; a_dec; a_dec = g_list_next(a_dec)) {
688 gchar *name = a_dec->data;
689 MMPLAYER_FREEIF(name);
691 g_list_free(player->audio_decoders);
692 player->audio_decoders = NULL;
695 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
701 __mmplayer_gapless_play_thread(gpointer data)
703 mmplayer_t *player = (mmplayer_t *)data;
704 mmplayer_gst_element_t *mainbin = NULL;
706 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
709 while (!player->gapless_play_thread_exit) {
710 LOGD("gapless play thread started. waiting for signal.");
711 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
713 LOGD("reconfigure pipeline for gapless play.");
715 if (player->gapless_play_thread_exit) {
716 if (player->gapless.reconfigure) {
717 player->gapless.reconfigure = false;
718 MMPLAYER_PLAYBACK_UNLOCK(player);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 MMHandleType attrs = 0;
1350 gint active_index = 0;
1353 MMPLAYER_RETURN_IF_FAIL(player);
1355 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1357 /* change track to active pad */
1358 active_index = player->selector[type].active_pad_index;
1359 if ((active_index != DEFAULT_TRACK) &&
1360 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1361 LOGW("failed to change %d type track to %d", type, active_index);
1362 player->selector[type].active_pad_index = DEFAULT_TRACK;
1366 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1367 attrs = MMPLAYER_GET_ATTRS(player);
1369 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1370 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1372 if (mm_attrs_commit_all(attrs))
1373 LOGW("failed to commit attrs.");
1375 LOGW("cannot get content attribute");
1384 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1389 if (!audio_selector) {
1390 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1392 /* in case the source is changed, output can be changed. */
1393 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1394 LOGD("remove previous audiobin if it exist");
1396 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1397 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1399 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1400 MMPLAYER_FREEIF(player->pipeline->audiobin);
1403 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1404 __mmplayer_pipeline_complete(NULL, player);
1409 /* apply the audio track information */
1410 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1412 /* create audio sink path */
1413 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1414 LOGE("failed to create audio sink path");
1423 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1426 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1428 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1429 LOGD("text path is not supproted");
1433 /* apply the text track information */
1434 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1436 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1437 player->has_closed_caption = TRUE;
1439 /* create text decode path */
1440 player->no_more_pad = TRUE;
1442 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1443 LOGE("failed to create text sink path");
1452 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1454 gint64 dur_bytes = 0L;
1457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1458 player->pipeline->mainbin && player->streamer, FALSE);
1460 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1461 LOGE("fail to get duration.");
1463 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1464 * use file information was already set on Q2 when it was created. */
1465 _mm_player_streaming_set_queue2(player->streamer,
1466 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1467 TRUE, /* use_buffering */
1468 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1469 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1476 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1478 mmplayer_t *player = NULL;
1479 GstElement *video_selector = NULL;
1480 GstElement *audio_selector = NULL;
1481 GstElement *text_selector = NULL;
1484 player = (mmplayer_t *)data;
1486 LOGD("no-more-pad signal handling");
1488 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1489 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1490 LOGW("player is shutting down");
1494 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1495 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1496 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1497 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1498 LOGE("failed to set queue2 buffering");
1503 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1504 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1505 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1507 if (!video_selector && !audio_selector && !text_selector) {
1508 LOGW("there is no selector");
1509 player->no_more_pad = TRUE;
1513 /* create video path followed by video-select */
1514 if (video_selector && !audio_selector && !text_selector)
1515 player->no_more_pad = TRUE;
1517 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1520 /* create audio path followed by audio-select */
1521 if (audio_selector && !text_selector)
1522 player->no_more_pad = TRUE;
1524 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1527 /* create text path followed by text-select */
1528 __mmplayer_create_text_sink_path(player, text_selector);
1531 if (player->gapless.reconfigure) {
1532 player->gapless.reconfigure = FALSE;
1533 MMPLAYER_PLAYBACK_UNLOCK(player);
1540 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1542 gboolean ret = FALSE;
1543 GstElement *pipeline = NULL;
1544 GstPad *sinkpad = NULL;
1547 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1550 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1552 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1554 LOGE("failed to get pad from sinkbin");
1560 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1561 LOGE("failed to link sinkbin for reusing");
1562 goto EXIT; /* exit either pass or fail */
1566 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1567 LOGE("failed to set state(READY) to sinkbin");
1572 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1573 LOGE("failed to add sinkbin to pipeline");
1578 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1579 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1584 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1585 LOGE("failed to set state(PAUSED) to sinkbin");
1594 gst_object_unref(GST_OBJECT(sinkpad));
1602 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1604 mmplayer_t *player = NULL;
1605 GstCaps *caps = NULL;
1606 gchar *caps_str = NULL;
1607 GstStructure *str = NULL;
1608 const gchar *name = NULL;
1609 GstElement *sinkbin = NULL;
1610 gboolean reusing = FALSE;
1611 gboolean caps_ret = TRUE;
1612 gchar *sink_pad_name = "sink";
1615 player = (mmplayer_t *)data;
1618 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1619 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1621 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1625 caps_str = gst_caps_to_string(caps);
1627 LOGD("detected mimetype : %s", name);
1629 if (strstr(name, "audio")) {
1630 if (player->pipeline->audiobin == NULL) {
1631 const gchar *audio_format = gst_structure_get_string(str, "format");
1633 LOGD("original audio format %s", audio_format);
1634 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1637 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1638 LOGE("failed to create audiobin. continuing without audio");
1642 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1643 LOGD("creating audiobin success");
1646 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1647 LOGD("reusing audiobin");
1648 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1650 } else if (strstr(name, "video")) {
1651 /* 1. zero copy is updated at _decode_pad_added()
1652 * 2. NULL surface type is handled in _decode_pad_added() */
1653 LOGD("zero copy %d", player->set_mode.video_zc);
1654 if (player->pipeline->videobin == NULL) {
1655 int surface_type = 0;
1656 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1657 LOGD("display_surface_type (%d)", surface_type);
1659 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1660 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1661 LOGE("failed to acquire video overlay resource");
1665 player->interrupted_by_resource = FALSE;
1667 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1668 LOGE("failed to create videobin. continuing without video");
1672 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1673 LOGD("creating videosink bin success");
1676 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1677 LOGD("re-using videobin");
1678 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1680 } else if (strstr(name, "text")) {
1681 if (player->pipeline->textbin == NULL) {
1682 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1683 LOGE("failed to create text sink bin. continuing without text");
1687 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1688 player->textsink_linked = 1;
1689 LOGD("creating textsink bin success");
1691 if (!player->textsink_linked) {
1692 LOGD("re-using textbin");
1694 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1695 player->textsink_linked = 1;
1697 /* linked textbin exist which means that the external subtitle path exist already */
1698 LOGW("ignoring internal subtutle since external subtitle is available");
1701 sink_pad_name = "text_sink";
1703 LOGW("unknown mime type %s, ignoring it", name);
1707 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1710 LOGD("[handle: %p] success to create and link sink bin", player);
1712 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1713 * streaming task. if the task blocked, then buffer will not flow to the next element
1714 *(autoplugging element). so this is special hack for streaming. please try to remove it
1716 /* dec stream count. we can remove fakesink if it's zero */
1717 if (player->num_dynamic_pad)
1718 player->num_dynamic_pad--;
1720 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1722 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1723 __mmplayer_pipeline_complete(NULL, player);
1727 MMPLAYER_FREEIF(caps_str);
1730 gst_caps_unref(caps);
1736 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1738 int required_angle = 0; /* Angle required for straight view */
1739 int rotation_angle = 0;
1741 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1742 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1744 /* Counter clockwise */
1745 switch (orientation) {
1750 required_angle = 270;
1753 required_angle = 180;
1756 required_angle = 90;
1760 rotation_angle = display_angle + required_angle;
1761 if (rotation_angle >= 360)
1762 rotation_angle -= 360;
1764 /* chech if supported or not */
1765 if (rotation_angle % 90) {
1766 LOGD("not supported rotation angle = %d", rotation_angle);
1770 switch (rotation_angle) {
1772 *value = MM_DISPLAY_ROTATION_NONE;
1775 *value = MM_DISPLAY_ROTATION_90;
1778 *value = MM_DISPLAY_ROTATION_180;
1781 *value = MM_DISPLAY_ROTATION_270;
1785 LOGD("setting rotation property value : %d", *value);
1791 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1793 int display_rotation = 0;
1794 gchar *org_orient = NULL;
1795 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1798 LOGE("cannot get content attribute");
1799 return MM_ERROR_PLAYER_INTERNAL;
1802 if (display_angle) {
1803 /* update user roation */
1804 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1806 /* Counter clockwise */
1807 switch (display_rotation) {
1808 case MM_DISPLAY_ROTATION_NONE:
1811 case MM_DISPLAY_ROTATION_90:
1812 *display_angle = 90;
1814 case MM_DISPLAY_ROTATION_180:
1815 *display_angle = 180;
1817 case MM_DISPLAY_ROTATION_270:
1818 *display_angle = 270;
1821 LOGW("wrong angle type : %d", display_rotation);
1824 LOGD("check user angle: %d", *display_angle);
1828 /* Counter clockwise */
1829 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1832 if (!strcmp(org_orient, "rotate-90"))
1834 else if (!strcmp(org_orient, "rotate-180"))
1836 else if (!strcmp(org_orient, "rotate-270"))
1839 LOGD("original rotation is %s", org_orient);
1841 LOGD("content_video_orientation get fail");
1844 LOGD("check orientation: %d", *orientation);
1847 return MM_ERROR_NONE;
1850 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1852 int rotation_value = 0;
1853 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1854 int display_angle = 0;
1857 /* check video sinkbin is created */
1858 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1861 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1863 /* get rotation value to set */
1864 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1865 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1866 LOGD("set video param : rotate %d", rotation_value);
1869 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1871 MMHandleType attrs = 0;
1875 /* check video sinkbin is created */
1876 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1879 attrs = MMPLAYER_GET_ATTRS(player);
1880 MMPLAYER_RETURN_IF_FAIL(attrs);
1882 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1883 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1884 LOGD("set video param : visible %d", visible);
1887 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1889 MMHandleType attrs = 0;
1890 int display_method = 0;
1893 /* check video sinkbin is created */
1894 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1897 attrs = MMPLAYER_GET_ATTRS(player);
1898 MMPLAYER_RETURN_IF_FAIL(attrs);
1900 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1901 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1902 LOGD("set video param : method %d", display_method);
1905 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1907 MMHandleType attrs = 0;
1908 void *handle = NULL;
1911 /* check video sinkbin is created */
1912 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1915 attrs = MMPLAYER_GET_ATTRS(player);
1916 MMPLAYER_RETURN_IF_FAIL(attrs);
1917 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1919 gst_video_overlay_set_video_roi_area(
1920 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1921 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1922 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1923 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1927 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1929 MMHandleType attrs = 0;
1930 void *handle = NULL;
1934 int win_roi_width = 0;
1935 int win_roi_height = 0;
1938 /* check video sinkbin is created */
1939 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1942 attrs = MMPLAYER_GET_ATTRS(player);
1943 MMPLAYER_RETURN_IF_FAIL(attrs);
1945 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1948 /* It should be set after setting window */
1949 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1950 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1951 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1952 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1954 /* After setting window handle, set display roi area */
1955 gst_video_overlay_set_display_roi_area(
1956 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1957 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1958 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1959 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1963 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1965 MMHandleType attrs = 0;
1966 void *handle = NULL;
1968 /* check video sinkbin is created */
1969 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1972 attrs = MMPLAYER_GET_ATTRS(player);
1973 MMPLAYER_RETURN_IF_FAIL(attrs);
1975 /* common case if using overlay surface */
1976 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1979 /* default is using wl_surface_id */
1980 unsigned int wl_surface_id = 0;
1981 wl_surface_id = *(int *)handle;
1982 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1983 gst_video_overlay_set_wl_window_wl_surface_id(
1984 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1987 /* FIXIT : is it error case? */
1988 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1993 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1995 gboolean update_all_param = FALSE;
1999 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2000 LOGW("videosink is not ready yet");
2001 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2004 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2005 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2006 return MM_ERROR_PLAYER_INTERNAL;
2009 LOGD("param_name : %s", param_name);
2010 if (!g_strcmp0(param_name, "update_all_param"))
2011 update_all_param = TRUE;
2013 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2014 __mmplayer_video_param_set_display_overlay(player);
2015 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2016 __mmplayer_video_param_set_display_method(player);
2017 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2018 __mmplayer_video_param_set_display_visible(player);
2019 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2020 __mmplayer_video_param_set_display_rotation(player);
2021 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2022 __mmplayer_video_param_set_roi_area(player);
2023 if (update_all_param)
2024 __mmplayer_video_param_set_video_roi_area(player);
2028 return MM_ERROR_NONE;
2032 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2034 gboolean disable_overlay = FALSE;
2035 mmplayer_t *player = (mmplayer_t *)hplayer;
2038 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2039 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2040 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2041 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2043 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2044 LOGW("Display control is not supported");
2045 return MM_ERROR_PLAYER_INTERNAL;
2048 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2050 if (audio_only == (bool)disable_overlay) {
2051 LOGE("It's the same with current setting: (%d)", audio_only);
2052 return MM_ERROR_NONE;
2056 LOGE("disable overlay");
2057 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2059 /* release overlay resource */
2060 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2061 LOGE("failed to release overlay resource");
2065 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2066 LOGE("failed to acquire video overlay resource");
2069 player->interrupted_by_resource = FALSE;
2071 LOGD("enable overlay");
2072 __mmplayer_video_param_set_display_overlay(player);
2073 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2078 return MM_ERROR_NONE;
2082 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2084 mmplayer_t *player = (mmplayer_t *)hplayer;
2085 gboolean disable_overlay = FALSE;
2089 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2090 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2091 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2092 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2093 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2095 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2096 LOGW("Display control is not supported");
2097 return MM_ERROR_PLAYER_INTERNAL;
2100 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2102 *paudio_only = (bool)disable_overlay;
2104 LOGD("audio_only : %d", *paudio_only);
2108 return MM_ERROR_NONE;
2112 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2114 GList *bucket = element_bucket;
2115 mmplayer_gst_element_t *element = NULL;
2116 mmplayer_gst_element_t *prv_element = NULL;
2117 GstElement *tee_element = NULL;
2118 gint successful_link_count = 0;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2124 prv_element = (mmplayer_gst_element_t *)bucket->data;
2125 bucket = bucket->next;
2127 for (; bucket; bucket = bucket->next) {
2128 element = (mmplayer_gst_element_t *)bucket->data;
2130 if (element && element->gst) {
2131 if (prv_element && prv_element->gst) {
2132 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2134 prv_element->gst = tee_element;
2136 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2137 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2138 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2142 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2143 LOGD("linking [%s] to [%s] success",
2144 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2145 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2146 successful_link_count++;
2147 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2148 LOGD("keep audio-tee element for next audio pipeline branch");
2149 tee_element = prv_element->gst;
2152 LOGD("linking [%s] to [%s] failed",
2153 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2154 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2160 prv_element = element;
2165 return successful_link_count;
2169 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2171 GList *bucket = element_bucket;
2172 mmplayer_gst_element_t *element = NULL;
2173 int successful_add_count = 0;
2177 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2178 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2180 for (; bucket; bucket = bucket->next) {
2181 element = (mmplayer_gst_element_t *)bucket->data;
2183 if (element && element->gst) {
2184 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2185 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2186 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2187 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2190 successful_add_count++;
2196 return successful_add_count;
2200 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2202 mmplayer_t *player = (mmplayer_t *)data;
2203 GstCaps *caps = NULL;
2204 GstStructure *str = NULL;
2206 gboolean caps_ret = TRUE;
2210 MMPLAYER_RETURN_IF_FAIL(pad);
2211 MMPLAYER_RETURN_IF_FAIL(unused);
2212 MMPLAYER_RETURN_IF_FAIL(data);
2214 caps = gst_pad_get_current_caps(pad);
2218 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2222 LOGD("name = %s", name);
2224 if (strstr(name, "audio")) {
2225 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2227 if (player->audio_stream_changed_cb) {
2228 LOGE("call the audio stream changed cb");
2229 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2231 } else if (strstr(name, "video")) {
2232 if ((name = gst_structure_get_string(str, "format")))
2233 player->set_mode.video_zc = name[0] == 'S';
2235 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2236 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2238 LOGW("invalid caps info");
2243 gst_caps_unref(caps);
2251 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2256 MMPLAYER_RETURN_IF_FAIL(player);
2258 if (player->audio_stream_buff_list) {
2259 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2260 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2263 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2264 __mmplayer_audio_stream_send_data(player, tmp);
2266 MMPLAYER_FREEIF(tmp->pcm_data);
2267 MMPLAYER_FREEIF(tmp);
2270 g_list_free(player->audio_stream_buff_list);
2271 player->audio_stream_buff_list = NULL;
2278 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2280 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2283 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2285 audio_stream.bitrate = a_buffer->bitrate;
2286 audio_stream.channel = a_buffer->channel;
2287 audio_stream.depth = a_buffer->depth;
2288 audio_stream.is_little_endian = a_buffer->is_little_endian;
2289 audio_stream.channel_mask = a_buffer->channel_mask;
2290 audio_stream.data_size = a_buffer->data_size;
2291 audio_stream.data = a_buffer->pcm_data;
2292 audio_stream.pcm_format = a_buffer->pcm_format;
2294 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2296 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2302 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2304 mmplayer_t *player = (mmplayer_t *)data;
2305 const gchar *pcm_format = NULL;
2309 gint endianness = 0;
2310 guint64 channel_mask = 0;
2311 void *a_data = NULL;
2313 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2314 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2318 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2320 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2321 a_data = mapinfo.data;
2322 a_size = mapinfo.size;
2324 GstCaps *caps = gst_pad_get_current_caps(pad);
2325 GstStructure *structure = gst_caps_get_structure(caps, 0);
2327 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2329 pcm_format = gst_structure_get_string(structure, "format");
2330 gst_structure_get_int(structure, "rate", &rate);
2331 gst_structure_get_int(structure, "channels", &channel);
2332 gst_structure_get_int(structure, "depth", &depth);
2333 gst_structure_get_int(structure, "endianness", &endianness);
2334 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2335 gst_caps_unref(GST_CAPS(caps));
2337 /* In case of the sync is false, use buffer list. *
2338 * The num of buffer list depends on the num of audio channels */
2339 if (player->audio_stream_buff_list) {
2340 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2341 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2343 if (channel_mask == tmp->channel_mask) {
2345 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2347 if (tmp->data_size + a_size < tmp->buff_size) {
2348 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2349 tmp->data_size += a_size;
2351 /* send data to client */
2352 __mmplayer_audio_stream_send_data(player, tmp);
2354 if (a_size > tmp->buff_size) {
2355 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2356 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2357 if (tmp->pcm_data == NULL) {
2358 LOGE("failed to realloc data.");
2361 tmp->buff_size = a_size;
2363 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2364 memcpy(tmp->pcm_data, a_data, a_size);
2365 tmp->data_size = a_size;
2370 LOGE("data is empty in list.");
2376 /* create new audio stream data for newly found audio channel */
2377 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2378 if (a_buffer == NULL) {
2379 LOGE("failed to alloc data.");
2382 a_buffer->bitrate = rate;
2383 a_buffer->channel = channel;
2384 a_buffer->depth = depth;
2385 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2386 a_buffer->channel_mask = channel_mask;
2387 a_buffer->data_size = a_size;
2388 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2390 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2391 /* If sync is FALSE, use buffer list to reduce the IPC. */
2392 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2393 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2394 if (a_buffer->pcm_data == NULL) {
2395 LOGE("failed to alloc data.");
2396 MMPLAYER_FREEIF(a_buffer);
2399 memcpy(a_buffer->pcm_data, a_data, a_size);
2401 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2403 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2405 /* If sync is TRUE, send data directly. */
2406 a_buffer->pcm_data = a_data;
2407 __mmplayer_audio_stream_send_data(player, a_buffer);
2408 MMPLAYER_FREEIF(a_buffer);
2412 gst_buffer_unmap(buffer, &mapinfo);
2417 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2419 mmplayer_t *player = (mmplayer_t *)data;
2420 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2421 GstPad *sinkpad = NULL;
2422 GstElement *queue = NULL, *sink = NULL;
2425 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2427 queue = gst_element_factory_make("queue", NULL);
2428 if (queue == NULL) {
2429 LOGD("fail make queue");
2433 sink = gst_element_factory_make("fakesink", NULL);
2435 LOGD("fail make fakesink");
2439 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2441 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2442 LOGW("failed to link queue & sink");
2446 sinkpad = gst_element_get_static_pad(queue, "sink");
2448 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2449 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2453 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2455 gst_object_unref(sinkpad);
2456 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2457 g_object_set(sink, "sync", TRUE, NULL);
2458 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2460 /* keep the first sink reference only */
2461 if (!audiobin[MMPLAYER_A_SINK].gst) {
2462 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2463 audiobin[MMPLAYER_A_SINK].gst = sink;
2467 _mmplayer_add_signal_connection(player,
2469 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2471 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2474 __mmplayer_add_sink(player, sink);
2476 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2477 LOGE("failed to sync state");
2481 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2482 LOGE("failed to sync state");
2490 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2492 gst_object_unref(GST_OBJECT(queue));
2496 gst_object_unref(GST_OBJECT(sink));
2500 gst_object_unref(GST_OBJECT(sinkpad));
2508 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2510 mmplayer_t *player = (mmplayer_t *)data;
2513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2515 player->no_more_pad = TRUE;
2516 __mmplayer_pipeline_complete(NULL, player);
2523 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2525 #define MAX_PROPS_LEN 128
2526 mmplayer_gst_element_t *audiobin = NULL;
2527 gint latency_mode = 0;
2528 gchar *stream_type = NULL;
2529 gchar *latency = NULL;
2531 gchar stream_props[MAX_PROPS_LEN] = {0,};
2532 GstStructure *props = NULL;
2535 * It should be set after player creation through attribute.
2536 * But, it can not be changed during playing.
2539 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2541 audiobin = player->pipeline->audiobin;
2543 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2544 if (player->sound.mute) {
2545 LOGD("mute enabled");
2546 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2549 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2550 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2553 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2555 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2556 stream_type, stream_id, player->client_pid);
2558 props = gst_structure_from_string(stream_props, NULL);
2559 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2560 LOGI("props result[%s].", stream_props);
2561 gst_structure_free(props);
2563 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2565 switch (latency_mode) {
2566 case AUDIO_LATENCY_MODE_LOW:
2567 latency = g_strndup("low", 3);
2569 case AUDIO_LATENCY_MODE_MID:
2570 latency = g_strndup("mid", 3);
2572 case AUDIO_LATENCY_MODE_HIGH:
2573 latency = g_strndup("high", 4);
2577 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2579 LOGD("audiosink property - latency=%s", latency);
2581 MMPLAYER_FREEIF(latency);
2587 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2589 mmplayer_gst_element_t *audiobin = NULL;
2592 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2594 audiobin = player->pipeline->audiobin;
2596 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2597 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2598 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2600 if (player->video360_yaw_radians <= M_PI &&
2601 player->video360_yaw_radians >= -M_PI &&
2602 player->video360_pitch_radians <= M_PI_2 &&
2603 player->video360_pitch_radians >= -M_PI_2) {
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2605 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2606 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2607 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2608 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2609 "source-orientation-y", player->video360_metadata.init_view_heading,
2610 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2617 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2619 mmplayer_gst_element_t *audiobin = NULL;
2620 GstPad *sink_pad = NULL;
2621 GstCaps *acaps = NULL;
2623 int pitch_control = 0;
2624 double pitch_value = 1.0;
2627 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2628 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2630 audiobin = player->pipeline->audiobin;
2632 LOGD("make element for normal audio playback");
2634 /* audio bin structure for playback. {} means optional.
2635 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2637 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2638 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2641 /* for pitch control */
2642 mm_attrs_multiple_get(player->attrs, NULL,
2643 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2644 MM_PLAYER_PITCH_VALUE, &pitch_value,
2647 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2648 if (pitch_control && (player->videodec_linked == 0)) {
2649 GstElementFactory *factory;
2651 factory = gst_element_factory_find("pitch");
2653 gst_object_unref(factory);
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2662 LOGW("there is no pitch element");
2667 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2669 /* replaygain volume */
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2671 if (player->sound.rg_enable)
2672 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2674 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2677 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2679 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2680 /* currently, only openalsink uses volume element */
2681 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2682 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2684 if (player->sound.mute) {
2685 LOGD("mute enabled");
2686 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2690 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2692 /* audio effect element. if audio effect is enabled */
2693 if ((strcmp(player->ini.audioeffect_element, ""))
2695 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2698 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2700 if ((!player->bypass_audio_effect)
2701 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2702 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2703 if (!_mmplayer_audio_effect_custom_apply(player))
2704 LOGI("apply audio effect(custom) setting success");
2708 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2709 && (player->set_mode.rich_audio)) {
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2714 /* create audio sink */
2715 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2716 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2717 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2719 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2720 if (player->is_360_feature_enabled &&
2721 player->is_content_spherical &&
2723 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2724 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2725 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2727 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2732 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2734 gst_caps_unref(acaps);
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2738 player->is_openal_plugin_used = TRUE;
2740 if (player->is_360_feature_enabled && player->is_content_spherical)
2741 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2745 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2746 (player->videodec_linked && player->ini.use_system_clock)) {
2747 LOGD("system clock will be used.");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2751 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2752 __mmplayer_gst_set_pulsesink_property(player);
2753 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2754 __mmplayer_gst_set_openalsink_property(player);
2757 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2758 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2760 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2761 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2762 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2763 gst_object_unref(GST_OBJECT(sink_pad));
2765 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2768 return MM_ERROR_NONE;
2770 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2772 return MM_ERROR_PLAYER_INTERNAL;
2776 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2778 mmplayer_gst_element_t *audiobin = NULL;
2779 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2781 gchar *dst_format = NULL;
2783 int dst_samplerate = 0;
2784 int dst_channels = 0;
2785 GstCaps *caps = NULL;
2786 char *caps_str = NULL;
2789 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2790 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2792 audiobin = player->pipeline->audiobin;
2794 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2796 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2798 [case 1] extract interleave audio pcm without playback
2799 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2800 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2802 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2804 [case 2] deinterleave for each channel without playback
2805 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2806 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2808 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2809 - fakesink (sync or not)
2812 [case 3] [case 1(sync only)] + playback
2813 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2815 * src - ... - tee - queue1 - playback path
2816 - queue2 - [case1 pipeline with sync]
2818 [case 4] [case 2(sync only)] + playback
2819 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2821 * src - ... - tee - queue1 - playback path
2822 - queue2 - [case2 pipeline with sync]
2826 /* 1. create tee and playback path
2827 'tee' should be added at first to copy the decoded stream
2829 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2831 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2833 /* tee - path 1 : for playback path */
2834 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2835 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2837 /* tee - path 2 : for extract path */
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2839 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2842 /* if there is tee, 'tee - path 2' is linked here */
2844 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2847 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2849 /* 2. decide the extract pcm format */
2850 mm_attrs_multiple_get(player->attrs, NULL,
2851 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2852 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2853 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2856 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2857 dst_format, dst_len, dst_samplerate, dst_channels);
2859 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2860 mm_attrs_multiple_get(player->attrs, NULL,
2861 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2862 "content_audio_samplerate", &dst_samplerate,
2863 "content_audio_channels", &dst_channels,
2866 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2867 dst_format, dst_len, dst_samplerate, dst_channels);
2869 /* If there is no enough information, set it to platform default value. */
2870 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2871 LOGD("set platform default format");
2872 dst_format = DEFAULT_PCM_OUT_FORMAT;
2874 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2875 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2878 /* 3. create capsfilter */
2879 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2880 caps = gst_caps_new_simple("audio/x-raw",
2881 "format", G_TYPE_STRING, dst_format,
2882 "rate", G_TYPE_INT, dst_samplerate,
2883 "channels", G_TYPE_INT, dst_channels,
2886 caps_str = gst_caps_to_string(caps);
2887 LOGD("new caps : %s", caps_str);
2889 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2892 gst_caps_unref(caps);
2893 MMPLAYER_FREEIF(caps_str);
2895 /* 4-1. create deinterleave to extract pcm for each channel */
2896 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2897 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2898 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2900 /* audiosink will be added after getting signal for each channel */
2901 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2902 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2903 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2904 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2905 player->no_more_pad = FALSE;
2907 /* 4-2. create fakesink to extract interlevaed pcm */
2908 LOGD("add audio fakesink for interleaved audio");
2909 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2910 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2911 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2912 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2914 _mmplayer_add_signal_connection(player,
2915 G_OBJECT(audiobin[extract_sink_id].gst),
2916 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2918 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2921 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2925 return MM_ERROR_NONE;
2927 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2929 return MM_ERROR_PLAYER_INTERNAL;
2933 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2935 int ret = MM_ERROR_NONE;
2936 mmplayer_gst_element_t *audiobin = NULL;
2937 GList *element_bucket = NULL;
2940 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2941 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2943 audiobin = player->pipeline->audiobin;
2945 if (player->build_audio_offload) { /* skip all the audio filters */
2946 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2948 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2949 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2950 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2952 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2956 /* FIXME: need to mention the supportable condition at API reference */
2957 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2958 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2960 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2962 if (ret != MM_ERROR_NONE)
2965 LOGD("success to make audio bin element");
2966 *bucket = element_bucket;
2969 return MM_ERROR_NONE;
2972 LOGE("failed to make audio bin element");
2973 g_list_free(element_bucket);
2977 return MM_ERROR_PLAYER_INTERNAL;
2981 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2983 mmplayer_gst_element_t *first_element = NULL;
2984 mmplayer_gst_element_t *audiobin = NULL;
2986 GstPad *ghostpad = NULL;
2987 GList *element_bucket = NULL;
2991 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2994 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2996 LOGE("failed to allocate memory for audiobin");
2997 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3001 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3002 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3003 if (!audiobin[MMPLAYER_A_BIN].gst) {
3004 LOGE("failed to create audiobin");
3009 player->pipeline->audiobin = audiobin;
3011 /* create audio filters and audiosink */
3012 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3015 /* adding created elements to bin */
3016 LOGD("adding created elements to bin");
3017 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3020 /* linking elements in the bucket by added order. */
3021 LOGD("Linking elements in the bucket by added order.");
3022 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3025 /* get first element's sinkpad for creating ghostpad */
3026 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3027 if (!first_element) {
3028 LOGE("failed to get first elem");
3032 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3034 LOGE("failed to get pad from first element of audiobin");
3038 ghostpad = gst_ghost_pad_new("sink", pad);
3040 LOGE("failed to create ghostpad");
3044 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3045 LOGE("failed to add ghostpad to audiobin");
3049 gst_object_unref(pad);
3051 g_list_free(element_bucket);
3054 return MM_ERROR_NONE;
3057 LOGD("ERROR : releasing audiobin");
3060 gst_object_unref(GST_OBJECT(pad));
3063 gst_object_unref(GST_OBJECT(ghostpad));
3066 g_list_free(element_bucket);
3068 /* release element which are not added to bin */
3069 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3070 /* NOTE : skip bin */
3071 if (audiobin[i].gst) {
3072 GstObject *parent = NULL;
3073 parent = gst_element_get_parent(audiobin[i].gst);
3076 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3077 audiobin[i].gst = NULL;
3079 gst_object_unref(GST_OBJECT(parent));
3083 /* release audiobin with it's childs */
3084 if (audiobin[MMPLAYER_A_BIN].gst)
3085 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3087 MMPLAYER_FREEIF(audiobin);
3089 player->pipeline->audiobin = NULL;
3091 return MM_ERROR_PLAYER_INTERNAL;
3095 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3097 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3101 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3103 int ret = MM_ERROR_NONE;
3105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3106 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3108 MMPLAYER_VIDEO_BO_LOCK(player);
3110 if (player->video_bo_list) {
3111 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3112 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3113 if (tmp && tmp->bo == bo) {
3115 LOGD("release bo %p", bo);
3116 tbm_bo_unref(tmp->bo);
3117 MMPLAYER_VIDEO_BO_UNLOCK(player);
3118 MMPLAYER_VIDEO_BO_SIGNAL(player);
3123 /* hw codec is running or the list was reset for DRC. */
3124 LOGW("there is no bo list.");
3126 MMPLAYER_VIDEO_BO_UNLOCK(player);
3128 LOGW("failed to find bo %p", bo);
3133 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3138 MMPLAYER_RETURN_IF_FAIL(player);
3140 MMPLAYER_VIDEO_BO_LOCK(player);
3141 if (player->video_bo_list) {
3142 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3143 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3144 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3147 tbm_bo_unref(tmp->bo);
3151 g_list_free(player->video_bo_list);
3152 player->video_bo_list = NULL;
3154 player->video_bo_size = 0;
3155 MMPLAYER_VIDEO_BO_UNLOCK(player);
3162 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3165 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3166 gboolean ret = TRUE;
3168 /* check DRC, if it is, destroy the prev bo list to create again */
3169 if (player->video_bo_size != size) {
3170 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3171 __mmplayer_video_stream_destroy_bo_list(player);
3172 player->video_bo_size = size;
3175 MMPLAYER_VIDEO_BO_LOCK(player);
3177 if ((!player->video_bo_list) ||
3178 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3180 /* create bo list */
3182 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3184 if (player->video_bo_list) {
3185 /* if bo list did not created all, try it again. */
3186 idx = g_list_length(player->video_bo_list);
3187 LOGD("bo list exist(len: %d)", idx);
3190 for (; idx < player->ini.num_of_video_bo; idx++) {
3191 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3193 LOGE("Fail to alloc bo_info.");
3196 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3198 LOGE("Fail to tbm_bo_alloc.");
3199 MMPLAYER_FREEIF(bo_info);
3202 bo_info->used = FALSE;
3203 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3206 /* update video num buffers */
3207 LOGD("video_num_buffers : %d", idx);
3208 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3209 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3212 MMPLAYER_VIDEO_BO_UNLOCK(player);
3218 /* get bo from list*/
3219 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3220 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3221 if (tmp && (tmp->used == FALSE)) {
3222 LOGD("found bo %p to use", tmp->bo);
3224 MMPLAYER_VIDEO_BO_UNLOCK(player);
3225 return tbm_bo_ref(tmp->bo);
3229 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3230 MMPLAYER_VIDEO_BO_UNLOCK(player);
3234 if (player->ini.video_bo_timeout <= 0) {
3235 MMPLAYER_VIDEO_BO_WAIT(player);
3237 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3238 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3245 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3247 mmplayer_t *player = (mmplayer_t *)data;
3249 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3251 /* send prerolled pkt */
3252 player->video_stream_prerolled = false;
3254 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3256 /* not to send prerolled pkt again */
3257 player->video_stream_prerolled = true;
3261 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3263 mmplayer_t *player = (mmplayer_t *)data;
3264 mmplayer_video_decoded_data_info_t *stream = NULL;
3265 GstMemory *mem = NULL;
3268 MMPLAYER_RETURN_IF_FAIL(player);
3269 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3271 if (player->video_stream_prerolled) {
3272 player->video_stream_prerolled = false;
3273 LOGD("skip the prerolled pkt not to send it again");
3277 /* clear stream data structure */
3278 stream = __mmplayer_create_stream_from_pad(pad);
3280 LOGE("failed to alloc stream");
3284 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3286 /* set size and timestamp */
3287 mem = gst_buffer_peek_memory(buffer, 0);
3288 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3289 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3291 /* check zero-copy */
3292 if (player->set_mode.video_zc &&
3293 player->set_mode.video_export &&
3294 gst_is_tizen_memory(mem)) {
3295 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3296 stream->internal_buffer = gst_buffer_ref(buffer);
3297 } else { /* sw codec */
3298 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3301 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3305 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3306 LOGE("failed to send video decoded data.");
3313 LOGE("release video stream resource.");
3314 if (gst_is_tizen_memory(mem)) {
3316 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3318 tbm_bo_unref(stream->bo[i]);
3321 /* unref gst buffer */
3322 if (stream->internal_buffer)
3323 gst_buffer_unref(stream->internal_buffer);
3326 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3328 MMPLAYER_FREEIF(stream);
3333 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3335 mmplayer_gst_element_t *videobin = NULL;
3338 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3340 videobin = player->pipeline->videobin;
3342 /* Set spatial media metadata and/or user settings to the element.
3344 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3345 "projection-type", player->video360_metadata.projection_type, NULL);
3347 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3348 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3350 if (player->video360_metadata.full_pano_width_pixels &&
3351 player->video360_metadata.full_pano_height_pixels &&
3352 player->video360_metadata.cropped_area_image_width &&
3353 player->video360_metadata.cropped_area_image_height) {
3354 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3355 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3356 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3357 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3358 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3359 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3360 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3364 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "horizontal-fov", player->video360_horizontal_fov,
3367 "vertical-fov", player->video360_vertical_fov, NULL);
3370 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3371 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3372 "zoom", 1.0f / player->video360_zoom, NULL);
3375 if (player->video360_yaw_radians <= M_PI &&
3376 player->video360_yaw_radians >= -M_PI &&
3377 player->video360_pitch_radians <= M_PI_2 &&
3378 player->video360_pitch_radians >= -M_PI_2) {
3379 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3380 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3381 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3382 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3383 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3384 "pose-yaw", player->video360_metadata.init_view_heading,
3385 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3388 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3389 "passthrough", !player->is_video360_enabled, NULL);
3396 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3398 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3399 GList *element_bucket = NULL;
3402 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3404 /* create video360 filter */
3405 if (player->is_360_feature_enabled && player->is_content_spherical) {
3406 LOGD("create video360 element");
3407 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3408 __mmplayer_gst_set_video360_property(player);
3412 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3413 LOGD("skip creating the videoconv and rotator");
3414 return MM_ERROR_NONE;
3417 /* in case of sw codec & overlay surface type, except 360 playback.
3418 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3419 LOGD("create video converter: %s", video_csc);
3420 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3423 *bucket = element_bucket;
3425 return MM_ERROR_NONE;
3427 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3428 g_list_free(element_bucket);
3432 return MM_ERROR_PLAYER_INTERNAL;
3436 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3438 gchar *factory_name = NULL;
3440 switch (surface_type) {
3441 case MM_DISPLAY_SURFACE_OVERLAY:
3442 if (strlen(player->ini.videosink_element_overlay) > 0)
3443 factory_name = player->ini.videosink_element_overlay;
3445 case MM_DISPLAY_SURFACE_REMOTE:
3446 case MM_DISPLAY_SURFACE_NULL:
3447 if (strlen(player->ini.videosink_element_fake) > 0)
3448 factory_name = player->ini.videosink_element_fake;
3451 LOGE("unidentified surface type");
3455 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3456 return factory_name;
3460 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3462 gchar *factory_name = NULL;
3463 mmplayer_gst_element_t *videobin = NULL;
3468 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3470 videobin = player->pipeline->videobin;
3471 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3473 attrs = MMPLAYER_GET_ATTRS(player);
3475 LOGE("cannot get content attribute");
3476 return MM_ERROR_PLAYER_INTERNAL;
3479 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3480 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3481 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3483 /* support shard memory with S/W codec on HawkP */
3484 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3485 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3486 "use-tbm", use_tbm, NULL);
3490 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3491 return MM_ERROR_PLAYER_INTERNAL;
3493 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3494 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3497 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3499 LOGD("disable last-sample");
3500 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3503 if (player->set_mode.video_export) {
3505 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3506 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3507 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3509 _mmplayer_add_signal_connection(player,
3510 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3511 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3513 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3516 _mmplayer_add_signal_connection(player,
3517 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3518 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3520 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3524 if (videobin[MMPLAYER_V_SINK].gst) {
3525 GstPad *sink_pad = NULL;
3526 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3528 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3529 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3530 gst_object_unref(GST_OBJECT(sink_pad));
3532 LOGE("failed to get sink pad from videosink");
3536 return MM_ERROR_NONE;
3541 * - video overlay surface(arm/x86) : tizenwlsink
3544 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3547 GList *element_bucket = NULL;
3548 mmplayer_gst_element_t *first_element = NULL;
3549 mmplayer_gst_element_t *videobin = NULL;
3550 gchar *videosink_factory_name = NULL;
3553 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3556 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3558 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3560 player->pipeline->videobin = videobin;
3563 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3564 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3565 if (!videobin[MMPLAYER_V_BIN].gst) {
3566 LOGE("failed to create videobin");
3570 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3573 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3574 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3576 /* additional setting for sink plug-in */
3577 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3578 LOGE("failed to set video property");
3582 /* store it as it's sink element */
3583 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3585 /* adding created elements to bin */
3586 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3587 LOGE("failed to add elements");
3591 /* Linking elements in the bucket by added order */
3592 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3593 LOGE("failed to link elements");
3597 /* get first element's sinkpad for creating ghostpad */
3598 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3599 if (!first_element) {
3600 LOGE("failed to get first element from bucket");
3604 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3606 LOGE("failed to get pad from first element");
3610 /* create ghostpad */
3611 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3612 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3613 LOGE("failed to add ghostpad to videobin");
3616 gst_object_unref(pad);
3618 /* done. free allocated variables */
3619 g_list_free(element_bucket);
3623 return MM_ERROR_NONE;
3626 LOGE("ERROR : releasing videobin");
3627 g_list_free(element_bucket);
3630 gst_object_unref(GST_OBJECT(pad));
3632 /* release videobin with it's childs */
3633 if (videobin[MMPLAYER_V_BIN].gst)
3634 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3636 MMPLAYER_FREEIF(videobin);
3637 player->pipeline->videobin = NULL;
3639 return MM_ERROR_PLAYER_INTERNAL;
3643 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3645 GList *element_bucket = NULL;
3646 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3648 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3649 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3650 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3651 "signal-handoffs", FALSE,
3654 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3655 _mmplayer_add_signal_connection(player,
3656 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3657 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3659 G_CALLBACK(__mmplayer_update_subtitle),
3662 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3663 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3665 if (!player->play_subtitle) {
3666 LOGD("add textbin sink as sink element of whole pipeline.");
3667 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3670 /* adding created elements to bin */
3671 LOGD("adding created elements to bin");
3672 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3673 LOGE("failed to add elements");
3677 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3678 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3679 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3681 /* linking elements in the bucket by added order. */
3682 LOGD("Linking elements in the bucket by added order.");
3683 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3684 LOGE("failed to link elements");
3688 /* done. free allocated variables */
3689 g_list_free(element_bucket);
3691 if (textbin[MMPLAYER_T_QUEUE].gst) {
3693 GstPad *ghostpad = NULL;
3695 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3697 LOGE("failed to get sink pad of text queue");
3701 ghostpad = gst_ghost_pad_new("text_sink", pad);
3702 gst_object_unref(pad);
3705 LOGE("failed to create ghostpad of textbin");
3709 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3710 LOGE("failed to add ghostpad to textbin");
3711 gst_object_unref(ghostpad);
3716 return MM_ERROR_NONE;
3719 g_list_free(element_bucket);
3721 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3722 LOGE("remove textbin sink from sink list");
3723 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3726 /* release element at __mmplayer_gst_create_text_sink_bin */
3727 return MM_ERROR_PLAYER_INTERNAL;
3731 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3733 mmplayer_gst_element_t *textbin = NULL;
3734 GList *element_bucket = NULL;
3735 int surface_type = 0;
3740 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3743 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3745 LOGE("failed to allocate memory for textbin");
3746 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3750 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3751 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3752 if (!textbin[MMPLAYER_T_BIN].gst) {
3753 LOGE("failed to create textbin");
3758 player->pipeline->textbin = textbin;
3761 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3762 LOGD("surface type for subtitle : %d", surface_type);
3763 switch (surface_type) {
3764 case MM_DISPLAY_SURFACE_OVERLAY:
3765 case MM_DISPLAY_SURFACE_NULL:
3766 case MM_DISPLAY_SURFACE_REMOTE:
3767 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3768 LOGE("failed to make plain text elements");
3779 return MM_ERROR_NONE;
3783 LOGD("ERROR : releasing textbin");
3785 g_list_free(element_bucket);
3787 /* release signal */
3788 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3790 /* release element which are not added to bin */
3791 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3792 /* NOTE : skip bin */
3793 if (textbin[i].gst) {
3794 GstObject *parent = NULL;
3795 parent = gst_element_get_parent(textbin[i].gst);
3798 gst_object_unref(GST_OBJECT(textbin[i].gst));
3799 textbin[i].gst = NULL;
3801 gst_object_unref(GST_OBJECT(parent));
3806 /* release textbin with it's childs */
3807 if (textbin[MMPLAYER_T_BIN].gst)
3808 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3810 MMPLAYER_FREEIF(player->pipeline->textbin);
3811 player->pipeline->textbin = NULL;
3814 return MM_ERROR_PLAYER_INTERNAL;
3818 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3820 mmplayer_gst_element_t *mainbin = NULL;
3821 mmplayer_gst_element_t *textbin = NULL;
3822 MMHandleType attrs = 0;
3823 GstElement *subsrc = NULL;
3824 GstElement *subparse = NULL;
3825 gchar *subtitle_uri = NULL;
3826 const gchar *charset = NULL;
3832 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3834 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3836 mainbin = player->pipeline->mainbin;
3838 attrs = MMPLAYER_GET_ATTRS(player);
3840 LOGE("cannot get content attribute");
3841 return MM_ERROR_PLAYER_INTERNAL;
3844 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3845 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3846 LOGE("subtitle uri is not proper filepath.");
3847 return MM_ERROR_PLAYER_INVALID_URI;
3850 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3851 LOGE("failed to get storage info of subtitle path");
3852 return MM_ERROR_PLAYER_INVALID_URI;
3855 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3857 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3858 player->subtitle_language_list = NULL;
3859 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3861 /* create the subtitle source */
3862 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3864 LOGE("failed to create filesrc element");
3867 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3869 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3870 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3872 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3873 LOGW("failed to add queue");
3874 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3875 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3876 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3881 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3883 LOGE("failed to create subparse element");
3887 charset = _mmplayer_get_charset(subtitle_uri);
3889 LOGD("detected charset is %s", charset);
3890 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3893 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3894 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3896 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3897 LOGW("failed to add subparse");
3898 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3899 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3900 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3904 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3905 LOGW("failed to link subsrc and subparse");
3909 player->play_subtitle = TRUE;
3910 player->adjust_subtitle_pos = 0;
3912 LOGD("play subtitle using subtitle file");
3914 if (player->pipeline->textbin == NULL) {
3915 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3916 LOGE("failed to create text sink bin. continuing without text");
3920 textbin = player->pipeline->textbin;
3922 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3923 LOGW("failed to add textbin");
3925 /* release signal */
3926 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3928 /* release textbin with it's childs */
3929 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3930 MMPLAYER_FREEIF(player->pipeline->textbin);
3931 player->pipeline->textbin = textbin = NULL;
3935 LOGD("link text input selector and textbin ghost pad");
3937 player->textsink_linked = 1;
3938 player->external_text_idx = 0;
3939 LOGI("textsink is linked");
3941 textbin = player->pipeline->textbin;
3942 LOGD("text bin has been created. reuse it.");
3943 player->external_text_idx = 1;
3946 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3947 LOGW("failed to link subparse and textbin");
3951 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3953 LOGE("failed to get sink pad from textsink to probe data");
3957 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3958 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3960 gst_object_unref(pad);
3963 /* create dot. for debugging */
3964 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3967 return MM_ERROR_NONE;
3970 /* release text pipeline resource */
3971 player->textsink_linked = 0;
3973 /* release signal */
3974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3976 if (player->pipeline->textbin) {
3977 LOGE("remove textbin");
3979 /* release textbin with it's childs */
3980 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3981 MMPLAYER_FREEIF(player->pipeline->textbin);
3982 player->pipeline->textbin = NULL;
3986 /* release subtitle elem */
3987 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3988 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3990 return MM_ERROR_PLAYER_INTERNAL;
3994 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3996 mmplayer_t *player = (mmplayer_t *)data;
3997 MMMessageParamType msg = {0, };
3998 GstClockTime duration = 0;
3999 gpointer text = NULL;
4000 guint text_size = 0;
4001 gboolean ret = TRUE;
4002 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4006 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4007 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4009 if (player->is_subtitle_force_drop) {
4010 LOGW("subtitle is dropped forcedly.");
4014 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4015 text = mapinfo.data;
4016 text_size = mapinfo.size;
4018 if (player->set_mode.subtitle_off) {
4019 LOGD("subtitle is OFF.");
4023 if (!text || (text_size == 0)) {
4024 LOGD("There is no subtitle to be displayed.");
4028 msg.data = (void *)text;
4030 duration = GST_BUFFER_DURATION(buffer);
4032 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4033 if (player->duration > GST_BUFFER_PTS(buffer))
4034 duration = player->duration - GST_BUFFER_PTS(buffer);
4037 LOGI("subtitle duration is invalid, subtitle duration change "
4038 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4040 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4042 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4044 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4045 gst_buffer_unmap(buffer, &mapinfo);
4052 static GstPadProbeReturn
4053 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4055 mmplayer_t *player = (mmplayer_t *)u_data;
4056 GstClockTime cur_timestamp = 0;
4057 gint64 adjusted_timestamp = 0;
4058 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4060 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4062 if (player->set_mode.subtitle_off) {
4063 LOGD("subtitle is OFF.");
4067 if (player->adjust_subtitle_pos == 0) {
4068 LOGD("nothing to do");
4072 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4073 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4075 if (adjusted_timestamp < 0) {
4076 LOGD("adjusted_timestamp under zero");
4081 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4082 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4083 GST_TIME_ARGS(cur_timestamp),
4084 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4086 return GST_PAD_PROBE_OK;
4090 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4094 /* check player and subtitlebin are created */
4095 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4096 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4098 if (position == 0) {
4099 LOGD("nothing to do");
4101 return MM_ERROR_NONE;
4104 /* check current postion */
4105 player->adjust_subtitle_pos = position;
4107 LOGD("save adjust_subtitle_pos in player");
4111 return MM_ERROR_NONE;
4115 * This function is to create audio or video pipeline for playing.
4117 * @param player [in] handle of player
4119 * @return This function returns zero on success.
4124 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4126 int ret = MM_ERROR_NONE;
4127 mmplayer_gst_element_t *mainbin = NULL;
4128 MMHandleType attrs = 0;
4131 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4133 /* get profile attribute */
4134 attrs = MMPLAYER_GET_ATTRS(player);
4136 LOGE("failed to get content attribute");
4140 /* create pipeline handles */
4141 if (player->pipeline) {
4142 LOGE("pipeline should be released before create new one");
4146 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4147 if (player->pipeline == NULL)
4150 /* create mainbin */
4151 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4152 if (mainbin == NULL)
4155 /* create pipeline */
4156 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4157 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4158 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4159 LOGE("failed to create pipeline");
4164 player->pipeline->mainbin = mainbin;
4166 /* create the source and decoder elements */
4167 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4168 ret = _mmplayer_gst_build_es_pipeline(player);
4170 ret = _mmplayer_gst_build_pipeline(player);
4172 if (ret != MM_ERROR_NONE) {
4173 LOGE("failed to create some elements");
4177 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4178 if (__mmplayer_check_subtitle(player)
4179 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4180 LOGE("failed to create text pipeline");
4183 ret = _mmplayer_gst_add_bus_watch(player);
4184 if (ret != MM_ERROR_NONE) {
4185 LOGE("failed to add bus watch");
4190 return MM_ERROR_NONE;
4193 __mmplayer_gst_destroy_pipeline(player);
4194 return MM_ERROR_PLAYER_INTERNAL;
4198 __mmplayer_reset_gapless_state(mmplayer_t *player)
4201 MMPLAYER_RETURN_IF_FAIL(player
4203 && player->pipeline->audiobin
4204 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4206 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4213 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4216 int ret = MM_ERROR_NONE;
4220 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4222 /* cleanup stuffs */
4223 MMPLAYER_FREEIF(player->type);
4224 player->no_more_pad = FALSE;
4225 player->num_dynamic_pad = 0;
4226 player->demux_pad_index = 0;
4228 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4229 player->subtitle_language_list = NULL;
4230 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4232 __mmplayer_reset_gapless_state(player);
4234 if (player->streamer) {
4235 _mm_player_streaming_initialize(player->streamer, FALSE);
4236 _mm_player_streaming_destroy(player->streamer);
4237 player->streamer = NULL;
4240 /* cleanup unlinked mime type */
4241 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4242 MMPLAYER_FREEIF(player->unlinked_video_mime);
4243 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4245 /* cleanup running stuffs */
4246 _mmplayer_cancel_eos_timer(player);
4248 /* cleanup gst stuffs */
4249 if (player->pipeline) {
4250 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4251 GstTagList *tag_list = player->pipeline->tag_list;
4253 /* first we need to disconnect all signal hander */
4254 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4257 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4258 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4259 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4260 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4261 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4262 gst_object_unref(bus);
4264 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4265 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4266 if (ret != MM_ERROR_NONE) {
4267 LOGE("fail to change state to NULL");
4268 return MM_ERROR_PLAYER_INTERNAL;
4271 LOGW("succeeded in changing state to NULL");
4273 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4276 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4277 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4279 /* free avsysaudiosink
4280 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4281 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4283 MMPLAYER_FREEIF(audiobin);
4284 MMPLAYER_FREEIF(videobin);
4285 MMPLAYER_FREEIF(textbin);
4286 MMPLAYER_FREEIF(mainbin);
4290 gst_tag_list_unref(tag_list);
4292 MMPLAYER_FREEIF(player->pipeline);
4294 MMPLAYER_FREEIF(player->album_art);
4296 if (player->v_stream_caps) {
4297 gst_caps_unref(player->v_stream_caps);
4298 player->v_stream_caps = NULL;
4301 if (player->a_stream_caps) {
4302 gst_caps_unref(player->a_stream_caps);
4303 player->a_stream_caps = NULL;
4306 if (player->s_stream_caps) {
4307 gst_caps_unref(player->s_stream_caps);
4308 player->s_stream_caps = NULL;
4310 _mmplayer_track_destroy(player);
4312 if (player->sink_elements)
4313 g_list_free(player->sink_elements);
4314 player->sink_elements = NULL;
4316 if (player->bufmgr) {
4317 tbm_bufmgr_deinit(player->bufmgr);
4318 player->bufmgr = NULL;
4321 LOGW("finished destroy pipeline");
4329 __mmplayer_gst_realize(mmplayer_t *player)
4332 int ret = MM_ERROR_NONE;
4336 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4338 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4340 ret = __mmplayer_gst_create_pipeline(player);
4342 LOGE("failed to create pipeline");
4346 /* set pipeline state to READY */
4347 /* NOTE : state change to READY must be performed sync. */
4348 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4349 ret = _mmplayer_gst_set_state(player,
4350 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4352 if (ret != MM_ERROR_NONE) {
4353 /* return error if failed to set state */
4354 LOGE("failed to set READY state");
4358 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4360 /* create dot before error-return. for debugging */
4361 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4369 __mmplayer_gst_unrealize(mmplayer_t *player)
4371 int ret = MM_ERROR_NONE;
4375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4377 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4378 MMPLAYER_PRINT_STATE(player);
4380 /* release miscellaneous information */
4381 __mmplayer_release_misc(player);
4383 /* destroy pipeline */
4384 ret = __mmplayer_gst_destroy_pipeline(player);
4385 if (ret != MM_ERROR_NONE) {
4386 LOGE("failed to destory pipeline");
4390 /* release miscellaneous information.
4391 these info needs to be released after pipeline is destroyed. */
4392 __mmplayer_release_misc_post(player);
4394 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4402 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4407 LOGW("set_message_callback is called with invalid player handle");
4408 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4411 player->msg_cb = callback;
4412 player->msg_cb_param = user_param;
4414 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4418 return MM_ERROR_NONE;
4422 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4424 int ret = MM_ERROR_NONE;
4429 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4430 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4431 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4433 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4435 if (strstr(uri, "es_buff://")) {
4436 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4437 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4438 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4439 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4441 tmp = g_ascii_strdown(uri, strlen(uri));
4442 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4443 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4445 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4447 } else if (strstr(uri, "mms://")) {
4448 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4449 } else if ((path = strstr(uri, "mem://"))) {
4450 ret = __mmplayer_set_mem_uri(data, path, param);
4452 ret = __mmplayer_set_file_uri(data, uri);
4455 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4456 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4457 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4458 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4460 /* dump parse result */
4461 SECURE_LOGW("incoming uri : %s", uri);
4462 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4463 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4471 __mmplayer_can_do_interrupt(mmplayer_t *player)
4473 if (!player || !player->pipeline || !player->attrs) {
4474 LOGW("not initialized");
4478 if (player->audio_decoded_cb) {
4479 LOGW("not support in pcm extraction mode");
4483 /* check if seeking */
4484 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4485 MMMessageParamType msg_param;
4486 memset(&msg_param, 0, sizeof(MMMessageParamType));
4487 msg_param.code = MM_ERROR_PLAYER_SEEK;
4488 player->seek_state = MMPLAYER_SEEK_NONE;
4489 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4493 /* check other thread */
4494 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4495 LOGW("locked already, cmd state : %d", player->cmd);
4497 /* check application command */
4498 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4499 LOGW("playing.. should wait cmd lock then, will be interrupted");
4501 /* lock will be released at mrp_resource_release_cb() */
4502 MMPLAYER_CMD_LOCK(player);
4505 LOGW("nothing to do");
4508 LOGW("can interrupt immediately");
4512 FAILED: /* with CMD UNLOCKED */
4515 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4520 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4523 mmplayer_t *player = NULL;
4524 MMMessageParamType msg = {0, };
4526 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4531 LOGE("user_data is null");
4534 player = (mmplayer_t *)user_data;
4536 if (!__mmplayer_can_do_interrupt(player)) {
4537 LOGW("no need to interrupt, so leave");
4538 /* FIXME: there is no way to avoid releasing resource. */
4542 player->interrupted_by_resource = TRUE;
4544 /* get last play position */
4545 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4546 msg.union_type = MM_MSG_UNION_TIME;
4547 msg.time.elapsed = pos;
4548 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4550 LOGW("failed to get play position.");
4553 LOGD("video resource conflict so, resource will be freed by unrealizing");
4554 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4555 LOGE("failed to unrealize");
4557 /* lock is called in __mmplayer_can_do_interrupt() */
4558 MMPLAYER_CMD_UNLOCK(player);
4560 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4561 player->hw_resource[res_idx] = NULL;
4565 return TRUE; /* release all the resources */
4569 __mmplayer_initialize_video_roi(mmplayer_t *player)
4571 player->video_roi.scale_x = 0.0;
4572 player->video_roi.scale_y = 0.0;
4573 player->video_roi.scale_width = 1.0;
4574 player->video_roi.scale_height = 1.0;
4578 _mmplayer_create_player(MMHandleType handle)
4580 int ret = MM_ERROR_PLAYER_INTERNAL;
4581 bool enabled = false;
4583 mmplayer_t *player = MM_PLAYER_CAST(handle);
4587 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4589 /* initialize player state */
4590 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4591 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4592 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4593 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4595 /* check current state */
4596 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4598 /* construct attributes */
4599 player->attrs = _mmplayer_construct_attribute(handle);
4601 if (!player->attrs) {
4602 LOGE("Failed to construct attributes");
4606 /* initialize gstreamer with configured parameter */
4607 if (!__mmplayer_init_gstreamer(player)) {
4608 LOGE("Initializing gstreamer failed");
4609 _mmplayer_deconstruct_attribute(handle);
4613 /* create lock. note that g_tread_init() has already called in gst_init() */
4614 g_mutex_init(&player->fsink_lock);
4616 /* create update tag lock */
4617 g_mutex_init(&player->update_tag_lock);
4619 /* create gapless play mutex */
4620 g_mutex_init(&player->gapless_play_thread_mutex);
4622 /* create gapless play cond */
4623 g_cond_init(&player->gapless_play_thread_cond);
4625 /* create gapless play thread */
4626 player->gapless_play_thread =
4627 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4628 if (!player->gapless_play_thread) {
4629 LOGE("failed to create gapless play thread");
4630 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4631 g_mutex_clear(&player->gapless_play_thread_mutex);
4632 g_cond_clear(&player->gapless_play_thread_cond);
4636 player->bus_msg_q = g_queue_new();
4637 if (!player->bus_msg_q) {
4638 LOGE("failed to create queue for bus_msg");
4639 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4643 ret = _mmplayer_initialize_video_capture(player);
4644 if (ret != MM_ERROR_NONE) {
4645 LOGE("failed to initialize video capture");
4649 /* initialize resource manager */
4650 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4651 __resource_release_cb, player, &player->resource_manager)
4652 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4653 LOGE("failed to initialize resource manager");
4654 ret = MM_ERROR_PLAYER_INTERNAL;
4658 /* create video bo lock and cond */
4659 g_mutex_init(&player->video_bo_mutex);
4660 g_cond_init(&player->video_bo_cond);
4662 /* create subtitle info lock and cond */
4663 g_mutex_init(&player->subtitle_info_mutex);
4664 g_cond_init(&player->subtitle_info_cond);
4666 player->streaming_type = STREAMING_SERVICE_NONE;
4668 /* give default value of audio effect setting */
4669 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4670 player->sound.rg_enable = false;
4671 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4673 player->play_subtitle = FALSE;
4674 player->has_closed_caption = FALSE;
4675 player->pending_resume = FALSE;
4676 if (player->ini.dump_element_keyword[0][0] == '\0')
4677 player->ini.set_dump_element_flag = FALSE;
4679 player->ini.set_dump_element_flag = TRUE;
4681 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4682 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4683 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4685 /* Set video360 settings to their defaults for just-created player.
4688 player->is_360_feature_enabled = FALSE;
4689 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4690 LOGI("spherical feature info: %d", enabled);
4692 player->is_360_feature_enabled = TRUE;
4694 LOGE("failed to get spherical feature info");
4697 player->is_content_spherical = FALSE;
4698 player->is_video360_enabled = TRUE;
4699 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4700 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4701 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4702 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4703 player->video360_zoom = 1.0f;
4704 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4705 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4707 __mmplayer_initialize_video_roi(player);
4709 /* set player state to null */
4710 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4711 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4715 return MM_ERROR_NONE;
4719 g_mutex_clear(&player->fsink_lock);
4720 /* free update tag lock */
4721 g_mutex_clear(&player->update_tag_lock);
4722 g_queue_free(player->bus_msg_q);
4723 player->bus_msg_q = NULL;
4724 /* free gapless play thread */
4725 if (player->gapless_play_thread) {
4726 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4727 player->gapless_play_thread_exit = TRUE;
4728 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4729 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4731 g_thread_join(player->gapless_play_thread);
4732 player->gapless_play_thread = NULL;
4734 g_mutex_clear(&player->gapless_play_thread_mutex);
4735 g_cond_clear(&player->gapless_play_thread_cond);
4738 /* release attributes */
4739 _mmplayer_deconstruct_attribute(handle);
4747 __mmplayer_init_gstreamer(mmplayer_t *player)
4749 static gboolean initialized = FALSE;
4750 static const int max_argc = 50;
4752 gchar **argv = NULL;
4753 gchar **argv2 = NULL;
4759 LOGD("gstreamer already initialized.");
4764 argc = malloc(sizeof(int));
4765 argv = malloc(sizeof(gchar *) * max_argc);
4766 argv2 = malloc(sizeof(gchar *) * max_argc);
4768 if (!argc || !argv || !argv2)
4771 memset(argv, 0, sizeof(gchar *) * max_argc);
4772 memset(argv2, 0, sizeof(gchar *) * max_argc);
4776 argv[0] = g_strdup("mmplayer");
4779 for (i = 0; i < 5; i++) {
4780 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4781 if (strlen(player->ini.gst_param[i]) > 0) {
4782 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4787 /* we would not do fork for scanning plugins */
4788 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4791 /* check disable registry scan */
4792 if (player->ini.skip_rescan) {
4793 argv[*argc] = g_strdup("--gst-disable-registry-update");
4797 /* check disable segtrap */
4798 if (player->ini.disable_segtrap) {
4799 argv[*argc] = g_strdup("--gst-disable-segtrap");
4803 LOGD("initializing gstreamer with following parameter");
4804 LOGD("argc : %d", *argc);
4807 for (i = 0; i < arg_count; i++) {
4809 LOGD("argv[%d] : %s", i, argv2[i]);
4812 /* initializing gstreamer */
4813 if (!gst_init_check(argc, &argv, &err)) {
4814 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4821 for (i = 0; i < arg_count; i++) {
4823 LOGD("release - argv[%d] : %s", i, argv2[i]);
4825 MMPLAYER_FREEIF(argv2[i]);
4828 MMPLAYER_FREEIF(argv);
4829 MMPLAYER_FREEIF(argv2);
4830 MMPLAYER_FREEIF(argc);
4840 for (i = 0; i < arg_count; i++) {
4841 LOGD("free[%d] : %s", i, argv2[i]);
4842 MMPLAYER_FREEIF(argv2[i]);
4845 MMPLAYER_FREEIF(argv);
4846 MMPLAYER_FREEIF(argv2);
4847 MMPLAYER_FREEIF(argc);
4853 __mmplayer_check_async_state_transition(mmplayer_t *player)
4855 GstState element_state = GST_STATE_VOID_PENDING;
4856 GstState element_pending_state = GST_STATE_VOID_PENDING;
4857 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4858 GstElement *element = NULL;
4859 gboolean async = FALSE;
4861 /* check player handle */
4862 MMPLAYER_RETURN_IF_FAIL(player &&
4864 player->pipeline->mainbin &&
4865 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4868 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4870 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4871 LOGD("don't need to check the pipeline state");
4875 MMPLAYER_PRINT_STATE(player);
4877 /* wait for state transition */
4878 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4879 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4881 if (ret == GST_STATE_CHANGE_FAILURE) {
4882 LOGE(" [%s] state : %s pending : %s",
4883 GST_ELEMENT_NAME(element),
4884 gst_element_state_get_name(element_state),
4885 gst_element_state_get_name(element_pending_state));
4887 /* dump state of all element */
4888 _mmplayer_dump_pipeline_state(player);
4893 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4898 _mmplayer_destroy(MMHandleType handle)
4900 mmplayer_t *player = MM_PLAYER_CAST(handle);
4904 /* check player handle */
4905 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4907 /* destroy can called at anytime */
4908 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4910 /* check async state transition */
4911 __mmplayer_check_async_state_transition(player);
4913 /* release gapless play thread */
4914 if (player->gapless_play_thread) {
4915 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4916 player->gapless_play_thread_exit = TRUE;
4917 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4918 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4920 LOGD("waitting for gapless play thread exit");
4921 g_thread_join(player->gapless_play_thread);
4922 g_mutex_clear(&player->gapless_play_thread_mutex);
4923 g_cond_clear(&player->gapless_play_thread_cond);
4924 LOGD("gapless play thread released");
4927 _mmplayer_release_video_capture(player);
4929 /* de-initialize resource manager */
4930 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4931 player->resource_manager))
4932 LOGE("failed to deinitialize resource manager");
4934 /* release pipeline */
4935 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4936 LOGE("failed to destory pipeline");
4937 return MM_ERROR_PLAYER_INTERNAL;
4940 g_queue_free(player->bus_msg_q);
4942 /* release subtitle info lock and cond */
4943 g_mutex_clear(&player->subtitle_info_mutex);
4944 g_cond_clear(&player->subtitle_info_cond);
4946 __mmplayer_release_dump_list(player->dump_list);
4948 /* release miscellaneous information */
4949 __mmplayer_release_misc(player);
4951 /* release miscellaneous information.
4952 these info needs to be released after pipeline is destroyed. */
4953 __mmplayer_release_misc_post(player);
4955 /* release attributes */
4956 _mmplayer_deconstruct_attribute(handle);
4959 g_mutex_clear(&player->fsink_lock);
4962 g_mutex_clear(&player->update_tag_lock);
4964 /* release video bo lock and cond */
4965 g_mutex_clear(&player->video_bo_mutex);
4966 g_cond_clear(&player->video_bo_cond);
4970 return MM_ERROR_NONE;
4974 _mmplayer_realize(MMHandleType hplayer)
4976 mmplayer_t *player = (mmplayer_t *)hplayer;
4979 MMHandleType attrs = 0;
4980 int ret = MM_ERROR_NONE;
4984 /* check player handle */
4985 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987 /* check current state */
4988 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4990 attrs = MMPLAYER_GET_ATTRS(player);
4992 LOGE("fail to get attributes.");
4993 return MM_ERROR_PLAYER_INTERNAL;
4995 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4996 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4998 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4999 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5001 if (ret != MM_ERROR_NONE) {
5002 LOGE("failed to parse profile");
5007 if (uri && (strstr(uri, "es_buff://"))) {
5008 if (strstr(uri, "es_buff://push_mode"))
5009 player->es_player_push_mode = TRUE;
5011 player->es_player_push_mode = FALSE;
5014 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5015 LOGW("mms protocol is not supported format.");
5016 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5019 if (MMPLAYER_IS_STREAMING(player))
5020 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5022 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5024 player->smooth_streaming = FALSE;
5025 player->videodec_linked = 0;
5026 player->audiodec_linked = 0;
5027 player->textsink_linked = 0;
5028 player->is_external_subtitle_present = FALSE;
5029 player->is_external_subtitle_added_now = FALSE;
5030 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5031 player->video360_metadata.is_spherical = -1;
5032 player->is_openal_plugin_used = FALSE;
5033 player->demux_pad_index = 0;
5034 player->subtitle_language_list = NULL;
5035 player->is_subtitle_force_drop = FALSE;
5037 _mmplayer_track_initialize(player);
5038 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5040 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5041 gint prebuffer_ms = 0, rebuffer_ms = 0;
5043 player->streamer = _mm_player_streaming_create();
5044 _mm_player_streaming_initialize(player->streamer, TRUE);
5046 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5047 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5049 if (prebuffer_ms > 0) {
5050 prebuffer_ms = MAX(prebuffer_ms, 1000);
5051 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5054 if (rebuffer_ms > 0) {
5055 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5056 rebuffer_ms = MAX(rebuffer_ms, 1000);
5057 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5060 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5061 player->streamer->buffering_req.rebuffer_time);
5064 /* realize pipeline */
5065 ret = __mmplayer_gst_realize(player);
5066 if (ret != MM_ERROR_NONE)
5067 LOGE("fail to realize the player.");
5069 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5077 _mmplayer_unrealize(MMHandleType hplayer)
5079 mmplayer_t *player = (mmplayer_t *)hplayer;
5080 int ret = MM_ERROR_NONE;
5084 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5086 MMPLAYER_CMD_UNLOCK(player);
5087 /* destroy the gst bus msg thread which is created during realize.
5088 this funct have to be called before getting cmd lock. */
5089 _mmplayer_bus_msg_thread_destroy(player);
5090 MMPLAYER_CMD_LOCK(player);
5092 /* check current state */
5093 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5095 /* check async state transition */
5096 __mmplayer_check_async_state_transition(player);
5098 /* unrealize pipeline */
5099 ret = __mmplayer_gst_unrealize(player);
5101 if (!player->interrupted_by_resource) {
5102 int rm_ret = MM_ERROR_NONE;
5103 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5105 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5106 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5107 if (rm_ret != MM_ERROR_NONE)
5108 LOGE("failed to release [%d] resources", res_idx);
5117 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5119 mmplayer_t *player = (mmplayer_t *)hplayer;
5121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5123 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5127 _mmplayer_get_state(MMHandleType hplayer, int *state)
5129 mmplayer_t *player = (mmplayer_t *)hplayer;
5131 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5133 *state = MMPLAYER_CURRENT_STATE(player);
5135 return MM_ERROR_NONE;
5139 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5141 GstElement *vol_element = NULL;
5142 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5145 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5146 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5148 /* check pipeline handle */
5149 if (!player->pipeline || !player->pipeline->audiobin) {
5150 LOGD("'%s' will be applied when audiobin is created", prop_name);
5152 /* NOTE : stored value will be used in create_audiobin
5153 * returning MM_ERROR_NONE here makes application to able to
5154 * set audio volume or mute at anytime.
5156 return MM_ERROR_NONE;
5159 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5160 volume_elem_id = MMPLAYER_A_SINK;
5162 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5164 LOGE("failed to get vol element %d", volume_elem_id);
5165 return MM_ERROR_PLAYER_INTERNAL;
5168 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5170 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5171 LOGE("there is no '%s' property", prop_name);
5172 return MM_ERROR_PLAYER_INTERNAL;
5175 if (!strcmp(prop_name, "volume")) {
5176 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5177 } else if (!strcmp(prop_name, "mute")) {
5178 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5180 LOGE("invalid property %s", prop_name);
5181 return MM_ERROR_PLAYER_INTERNAL;
5184 return MM_ERROR_NONE;
5188 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5190 int ret = MM_ERROR_NONE;
5191 mmplayer_t *player = (mmplayer_t *)hplayer;
5194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5196 LOGD("volume = %f", volume);
5198 /* invalid factor range or not */
5199 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5200 LOGE("Invalid volume value");
5201 return MM_ERROR_INVALID_ARGUMENT;
5204 player->sound.volume = volume;
5206 ret = __mmplayer_gst_set_volume_property(player, "volume");
5213 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5215 mmplayer_t *player = (mmplayer_t *)hplayer;
5219 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5220 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5222 *volume = player->sound.volume;
5224 LOGD("current vol = %f", *volume);
5227 return MM_ERROR_NONE;
5231 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5233 int ret = MM_ERROR_NONE;
5234 mmplayer_t *player = (mmplayer_t *)hplayer;
5237 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5239 LOGD("mute = %d", mute);
5241 player->sound.mute = mute;
5243 ret = __mmplayer_gst_set_volume_property(player, "mute");
5250 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5252 mmplayer_t *player = (mmplayer_t *)hplayer;
5256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5257 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5259 *mute = player->sound.mute;
5261 LOGD("current mute = %d", *mute);
5265 return MM_ERROR_NONE;
5269 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5271 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5277 player->audio_stream_changed_cb = callback;
5278 player->audio_stream_changed_cb_user_param = user_param;
5279 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5283 return MM_ERROR_NONE;
5287 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5289 mmplayer_t *player = (mmplayer_t *)hplayer;
5293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5295 player->audio_decoded_cb = callback;
5296 player->audio_decoded_cb_user_param = user_param;
5297 player->audio_extract_opt = opt;
5298 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5302 return MM_ERROR_NONE;
5306 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5308 mmplayer_t *player = (mmplayer_t *)hplayer;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 if (callback && !player->bufmgr)
5315 player->bufmgr = tbm_bufmgr_init(-1);
5317 player->set_mode.video_export = (callback) ? true : false;
5318 player->video_decoded_cb = callback;
5319 player->video_decoded_cb_user_param = user_param;
5321 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5325 return MM_ERROR_NONE;
5329 _mmplayer_start(MMHandleType hplayer)
5331 mmplayer_t *player = (mmplayer_t *)hplayer;
5332 gint ret = MM_ERROR_NONE;
5336 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338 /* check current state */
5339 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5341 /* start pipeline */
5342 ret = _mmplayer_gst_start(player);
5343 if (ret != MM_ERROR_NONE)
5344 LOGE("failed to start player.");
5346 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5347 LOGD("force playing start even during buffering");
5348 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5356 /* NOTE: post "not supported codec message" to application
5357 * when one codec is not found during AUTOPLUGGING in MSL.
5358 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5359 * And, if any codec is not found, don't send message here.
5360 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5363 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5365 MMMessageParamType msg_param;
5366 memset(&msg_param, 0, sizeof(MMMessageParamType));
5367 gboolean post_msg_direct = FALSE;
5371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5373 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5374 player->not_supported_codec, player->can_support_codec);
5376 if (player->not_found_demuxer) {
5377 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5378 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5380 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5381 MMPLAYER_FREEIF(msg_param.data);
5383 return MM_ERROR_NONE;
5386 if (player->not_supported_codec) {
5387 if (player->can_support_codec) {
5388 // There is one codec to play
5389 post_msg_direct = TRUE;
5391 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5392 post_msg_direct = TRUE;
5395 if (post_msg_direct) {
5396 MMMessageParamType msg_param;
5397 memset(&msg_param, 0, sizeof(MMMessageParamType));
5399 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5400 LOGW("not found AUDIO codec, posting error code to application.");
5402 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5403 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5404 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5405 LOGW("not found VIDEO codec, posting error code to application.");
5407 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5408 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5411 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5413 MMPLAYER_FREEIF(msg_param.data);
5415 return MM_ERROR_NONE;
5417 // no any supported codec case
5418 LOGW("not found any codec, posting error code to application.");
5420 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5421 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5422 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5424 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5425 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5428 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5430 MMPLAYER_FREEIF(msg_param.data);
5436 return MM_ERROR_NONE;
5440 __mmplayer_check_pipeline(mmplayer_t *player)
5442 GstState element_state = GST_STATE_VOID_PENDING;
5443 GstState element_pending_state = GST_STATE_VOID_PENDING;
5445 int ret = MM_ERROR_NONE;
5447 if (!player->gapless.reconfigure)
5450 LOGW("pipeline is under construction.");
5452 MMPLAYER_PLAYBACK_LOCK(player);
5453 MMPLAYER_PLAYBACK_UNLOCK(player);
5455 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5457 /* wait for state transition */
5458 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5459 if (ret == GST_STATE_CHANGE_FAILURE)
5460 LOGE("failed to change pipeline state within %d sec", timeout);
5463 /* NOTE : it should be able to call 'stop' anytime*/
5465 _mmplayer_stop(MMHandleType hplayer)
5467 mmplayer_t *player = (mmplayer_t *)hplayer;
5468 int ret = MM_ERROR_NONE;
5472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5474 /* check current state */
5475 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5477 /* check pipline building state */
5478 __mmplayer_check_pipeline(player);
5479 __mmplayer_reset_gapless_state(player);
5481 /* NOTE : application should not wait for EOS after calling STOP */
5482 _mmplayer_cancel_eos_timer(player);
5485 player->seek_state = MMPLAYER_SEEK_NONE;
5488 ret = _mmplayer_gst_stop(player);
5490 if (ret != MM_ERROR_NONE)
5491 LOGE("failed to stop player.");
5499 _mmplayer_pause(MMHandleType hplayer)
5501 mmplayer_t *player = (mmplayer_t *)hplayer;
5502 gint64 pos_nsec = 0;
5503 gboolean async = FALSE;
5504 gint ret = MM_ERROR_NONE;
5508 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5510 /* check current state */
5511 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5513 /* check pipline building state */
5514 __mmplayer_check_pipeline(player);
5516 switch (MMPLAYER_CURRENT_STATE(player)) {
5517 case MM_PLAYER_STATE_READY:
5519 /* check prepare async or not.
5520 * In the case of streaming playback, it's recommned to avoid blocking wait.
5522 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5523 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5525 /* Changing back sync of rtspsrc to async */
5526 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5527 LOGD("async prepare working mode for rtsp");
5533 case MM_PLAYER_STATE_PLAYING:
5535 /* NOTE : store current point to overcome some bad operation
5536 *(returning zero when getting current position in paused state) of some
5539 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5540 LOGW("getting current position failed in paused");
5542 player->last_position = pos_nsec;
5544 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5545 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5546 This causes problem is position calculation during normal pause resume scenarios also.
5547 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5548 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5549 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5550 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5556 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5557 LOGD("doing async pause in case of ms buff src");
5561 /* pause pipeline */
5562 ret = _mmplayer_gst_pause(player, async);
5564 if (ret != MM_ERROR_NONE)
5565 LOGE("failed to pause player. ret : 0x%x", ret);
5567 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5568 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5569 LOGE("failed to update display_rotation");
5577 /* in case of streaming, pause could take long time.*/
5579 _mmplayer_abort_pause(MMHandleType hplayer)
5581 mmplayer_t *player = (mmplayer_t *)hplayer;
5582 int ret = MM_ERROR_NONE;
5586 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5588 player->pipeline->mainbin,
5589 MM_ERROR_PLAYER_NOT_INITIALIZED);
5591 LOGD("set the pipeline state to READY");
5593 /* set state to READY */
5594 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5595 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5596 if (ret != MM_ERROR_NONE) {
5597 LOGE("fail to change state to READY");
5598 return MM_ERROR_PLAYER_INTERNAL;
5601 LOGD("succeeded in changing state to READY");
5606 _mmplayer_resume(MMHandleType hplayer)
5608 mmplayer_t *player = (mmplayer_t *)hplayer;
5609 int ret = MM_ERROR_NONE;
5610 gboolean async = FALSE;
5614 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5616 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5617 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5618 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5622 /* Changing back sync mode rtspsrc to async */
5623 LOGD("async resume for rtsp case");
5627 /* check current state */
5628 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5630 ret = _mmplayer_gst_resume(player, async);
5631 if (ret != MM_ERROR_NONE)
5632 LOGE("failed to resume player.");
5634 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5635 LOGD("force resume even during buffering");
5636 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5645 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5647 mmplayer_t *player = (mmplayer_t *)hplayer;
5648 gint64 pos_nsec = 0;
5649 int ret = MM_ERROR_NONE;
5651 signed long long start = 0, stop = 0;
5652 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5655 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5656 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5658 /* The sound of video is not supported under 0.0 and over 2.0. */
5659 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5660 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5663 _mmplayer_set_mute(hplayer, mute);
5665 if (player->playback_rate == rate)
5666 return MM_ERROR_NONE;
5668 /* If the position is reached at start potion during fast backward, EOS is posted.
5669 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5671 player->playback_rate = rate;
5673 current_state = MMPLAYER_CURRENT_STATE(player);
5675 if (current_state != MM_PLAYER_STATE_PAUSED)
5676 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5678 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5680 if ((current_state == MM_PLAYER_STATE_PAUSED)
5681 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5682 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5683 pos_nsec = player->last_position;
5688 stop = GST_CLOCK_TIME_NONE;
5690 start = GST_CLOCK_TIME_NONE;
5694 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5695 player->playback_rate,
5697 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5698 GST_SEEK_TYPE_SET, start,
5699 GST_SEEK_TYPE_SET, stop)) {
5700 LOGE("failed to set speed playback");
5701 return MM_ERROR_PLAYER_SEEK;
5704 LOGD("succeeded to set speed playback as %0.1f", rate);
5708 return MM_ERROR_NONE;;
5712 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5714 mmplayer_t *player = (mmplayer_t *)hplayer;
5715 int ret = MM_ERROR_NONE;
5719 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5721 /* check pipline building state */
5722 __mmplayer_check_pipeline(player);
5724 ret = _mmplayer_gst_set_position(player, position, FALSE);
5732 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5734 mmplayer_t *player = (mmplayer_t *)hplayer;
5735 int ret = MM_ERROR_NONE;
5737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5738 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5740 if (g_strrstr(player->type, "video/mpegts"))
5741 __mmplayer_update_duration_value(player);
5743 *duration = player->duration;
5748 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5750 mmplayer_t *player = (mmplayer_t *)hplayer;
5751 int ret = MM_ERROR_NONE;
5753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5755 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5761 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5763 mmplayer_t *player = (mmplayer_t *)hplayer;
5764 int ret = MM_ERROR_NONE;
5768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5770 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5778 __mmplayer_is_midi_type(gchar *str_caps)
5780 if ((g_strrstr(str_caps, "audio/midi")) ||
5781 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5782 (g_strrstr(str_caps, "application/x-smaf")) ||
5783 (g_strrstr(str_caps, "audio/x-imelody")) ||
5784 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5785 (g_strrstr(str_caps, "audio/xmf")) ||
5786 (g_strrstr(str_caps, "audio/mxmf"))) {
5795 __mmplayer_is_only_mp3_type(gchar *str_caps)
5797 if (g_strrstr(str_caps, "application/x-id3") ||
5798 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5804 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5806 GstStructure *caps_structure = NULL;
5807 gint samplerate = 0;
5811 MMPLAYER_RETURN_IF_FAIL(player && caps);
5813 caps_structure = gst_caps_get_structure(caps, 0);
5815 /* set stream information */
5816 gst_structure_get_int(caps_structure, "rate", &samplerate);
5817 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5819 gst_structure_get_int(caps_structure, "channels", &channels);
5820 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5822 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5826 __mmplayer_update_content_type_info(mmplayer_t *player)
5829 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5831 if (__mmplayer_is_midi_type(player->type)) {
5832 player->bypass_audio_effect = TRUE;
5836 if (!player->streamer) {
5837 LOGD("no need to check streaming type");
5841 if (g_strrstr(player->type, "application/x-hls")) {
5842 /* If it can't know exact type when it parses uri because of redirection case,
5843 * it will be fixed by typefinder or when doing autoplugging.
5845 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5846 player->streamer->is_adaptive_streaming = TRUE;
5847 } else if (g_strrstr(player->type, "application/dash+xml")) {
5848 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5849 player->streamer->is_adaptive_streaming = TRUE;
5852 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5853 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5854 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5856 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5857 if (player->streamer->is_adaptive_streaming)
5858 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5860 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5864 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5869 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5870 GstCaps *caps, gpointer data)
5872 mmplayer_t *player = (mmplayer_t *)data;
5877 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5879 /* store type string */
5880 MMPLAYER_FREEIF(player->type);
5881 player->type = gst_caps_to_string(caps);
5883 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5884 player, player->type, probability, gst_caps_get_size(caps));
5886 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5887 (g_strrstr(player->type, "audio/x-raw-int"))) {
5888 LOGE("not support media format");
5890 if (player->msg_posted == FALSE) {
5891 MMMessageParamType msg_param;
5892 memset(&msg_param, 0, sizeof(MMMessageParamType));
5894 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5895 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5897 /* don't post more if one was sent already */
5898 player->msg_posted = TRUE;
5903 __mmplayer_update_content_type_info(player);
5905 pad = gst_element_get_static_pad(tf, "src");
5907 LOGE("fail to get typefind src pad.");
5911 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5912 gboolean async = FALSE;
5913 LOGE("failed to autoplug %s", player->type);
5915 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5917 if (async && player->msg_posted == FALSE)
5918 __mmplayer_handle_missed_plugin(player);
5922 gst_object_unref(GST_OBJECT(pad));
5930 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5932 GstElement *decodebin = NULL;
5936 /* create decodebin */
5937 decodebin = gst_element_factory_make("decodebin", NULL);
5940 LOGE("fail to create decodebin");
5944 /* raw pad handling signal */
5945 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5946 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5948 /* no-more-pad pad handling signal */
5949 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5950 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5952 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5953 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5955 /* This signal is emitted when a pad for which there is no further possible
5956 decoding is added to the decodebin.*/
5957 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5958 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5960 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5961 before looking for any elements that can handle that stream.*/
5962 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5963 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5965 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5966 before looking for any elements that can handle that stream.*/
5967 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5968 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5970 /* This signal is emitted once decodebin has finished decoding all the data.*/
5971 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5972 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5974 /* This signal is emitted when a element is added to the bin.*/
5975 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5976 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5983 __mmplayer_gst_make_queue2(mmplayer_t *player)
5985 GstElement *queue2 = NULL;
5986 gint64 dur_bytes = 0L;
5987 mmplayer_gst_element_t *mainbin = NULL;
5988 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5991 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5993 mainbin = player->pipeline->mainbin;
5995 queue2 = gst_element_factory_make("queue2", "queue2");
5997 LOGE("failed to create buffering queue element");
6001 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6002 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6004 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6006 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6007 * skip the pull mode(file or ring buffering) setting. */
6008 if (dur_bytes > 0) {
6009 if (!g_strrstr(player->type, "video/mpegts")) {
6010 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6011 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6017 _mm_player_streaming_set_queue2(player->streamer,
6021 (guint64)dur_bytes); /* no meaning at the moment */
6027 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6029 mmplayer_gst_element_t *mainbin = NULL;
6030 GstElement *decodebin = NULL;
6031 GstElement *queue2 = NULL;
6032 GstPad *sinkpad = NULL;
6033 GstPad *qsrcpad = NULL;
6036 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6038 mainbin = player->pipeline->mainbin;
6040 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6042 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6043 LOGW("need to check: muxed buffer is not null");
6046 queue2 = __mmplayer_gst_make_queue2(player);
6048 LOGE("failed to make queue2");
6052 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6053 LOGE("failed to add buffering queue");
6057 sinkpad = gst_element_get_static_pad(queue2, "sink");
6058 qsrcpad = gst_element_get_static_pad(queue2, "src");
6060 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6061 LOGE("failed to link [%s:%s]-[%s:%s]",
6062 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6066 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6067 LOGE("failed to sync queue2 state with parent");
6071 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6072 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6076 gst_object_unref(GST_OBJECT(sinkpad));
6080 /* create decodebin */
6081 decodebin = _mmplayer_gst_make_decodebin(player);
6083 LOGE("failed to make decodebin");
6087 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6088 LOGE("failed to add decodebin");
6092 /* to force caps on the decodebin element and avoid reparsing stuff by
6093 * typefind. It also avoids a deadlock in the way typefind activates pads in
6094 * the state change */
6095 g_object_set(decodebin, "sink-caps", caps, NULL);
6097 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6099 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6100 LOGE("failed to link [%s:%s]-[%s:%s]",
6101 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6105 gst_object_unref(GST_OBJECT(sinkpad));
6107 gst_object_unref(GST_OBJECT(qsrcpad));
6110 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6111 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6113 /* set decodebin property about buffer in streaming playback. *
6114 * in case of HLS/DASH, it does not need to have big buffer *
6115 * because it is kind of adaptive streaming. */
6116 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6117 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6118 gint high_percent = 0;
6120 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6121 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6123 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6125 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6127 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6128 "high-percent", high_percent,
6129 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6130 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6131 "max-size-buffers", 0, NULL); // disable or automatic
6134 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6135 LOGE("failed to sync decodebin state with parent");
6146 gst_object_unref(GST_OBJECT(sinkpad));
6149 gst_object_unref(GST_OBJECT(qsrcpad));
6152 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6153 * You need to explicitly set elements to the NULL state before
6154 * dropping the final reference, to allow them to clean up.
6156 gst_element_set_state(queue2, GST_STATE_NULL);
6158 /* And, it still has a parent "player".
6159 * You need to let the parent manage the object instead of unreffing the object directly.
6161 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6162 gst_object_unref(queue2);
6167 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6168 * You need to explicitly set elements to the NULL state before
6169 * dropping the final reference, to allow them to clean up.
6171 gst_element_set_state(decodebin, GST_STATE_NULL);
6173 /* And, it still has a parent "player".
6174 * You need to let the parent manage the object instead of unreffing the object directly.
6177 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6178 gst_object_unref(decodebin);
6186 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6190 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6191 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6193 LOGD("class : %s, mime : %s", factory_class, mime);
6195 /* add missing plugin */
6196 /* NOTE : msl should check missing plugin for image mime type.
6197 * Some motion jpeg clips can have playable audio track.
6198 * So, msl have to play audio after displaying popup written video format not supported.
6200 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6201 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6202 LOGD("not found demuxer");
6203 player->not_found_demuxer = TRUE;
6204 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6210 if (!g_strrstr(factory_class, "Demuxer")) {
6211 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6212 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6213 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6215 /* check that clip have multi tracks or not */
6216 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6217 LOGD("video plugin is already linked");
6219 LOGW("add VIDEO to missing plugin");
6220 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6221 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6223 } else if (g_str_has_prefix(mime, "audio")) {
6224 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6225 LOGD("audio plugin is already linked");
6227 LOGW("add AUDIO to missing plugin");
6228 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6229 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6237 return MM_ERROR_NONE;
6241 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6243 mmplayer_t *player = (mmplayer_t *)data;
6247 MMPLAYER_RETURN_IF_FAIL(player);
6249 /* remove fakesink. */
6250 if (!_mmplayer_gst_remove_fakesink(player,
6251 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6252 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6253 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6254 * source element are not same. To overcome this situation, this function will called
6255 * several places and several times. Therefore, this is not an error case.
6260 LOGD("[handle: %p] pipeline has completely constructed", player);
6262 if ((player->ini.async_start) &&
6263 (player->msg_posted == FALSE) &&
6264 (player->cmd >= MMPLAYER_COMMAND_START))
6265 __mmplayer_handle_missed_plugin(player);
6267 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6271 __mmplayer_check_profile(void)
6274 static int profile_tv = -1;
6276 if (__builtin_expect(profile_tv != -1, 1))
6279 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6280 switch (*profileName) {
6295 __mmplayer_get_next_uri(mmplayer_t *player)
6297 mmplayer_parse_profile_t profile;
6299 guint num_of_list = 0;
6302 num_of_list = g_list_length(player->uri_info.uri_list);
6303 uri_idx = player->uri_info.uri_idx;
6305 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6306 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6307 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6309 LOGW("next uri does not exist");
6313 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6314 LOGE("failed to parse profile");
6318 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6319 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6320 LOGW("uri type is not supported(%d)", profile.uri_type);
6324 LOGD("success to find next uri %d", uri_idx);
6328 if (uri_idx == num_of_list) {
6329 LOGE("failed to find next uri");
6333 player->uri_info.uri_idx = uri_idx;
6334 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6336 if (mm_attrs_commit_all(player->attrs)) {
6337 LOGE("failed to commit");
6341 SECURE_LOGD("next playback uri: %s", uri);
6346 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6348 #define REPEAT_COUNT_INFINITE -1
6349 #define REPEAT_COUNT_MIN 2
6350 #define ORIGINAL_URI_ONLY 1
6352 MMHandleType attrs = 0;
6356 guint num_of_uri = 0;
6357 int profile_tv = -1;
6361 LOGD("checking for gapless play option");
6363 if (player->build_audio_offload) {
6364 LOGE("offload path is not supportable.");
6368 if (player->pipeline->textbin) {
6369 LOGE("subtitle path is enabled. gapless play is not supported.");
6373 attrs = MMPLAYER_GET_ATTRS(player);
6375 LOGE("fail to get attributes.");
6379 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6381 /* gapless playback is not supported in case of video at TV profile. */
6382 profile_tv = __mmplayer_check_profile();
6383 if (profile_tv && video) {
6384 LOGW("not support video gapless playback");
6388 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6389 LOGE("failed to get play count");
6391 if (mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless) != MM_ERROR_NONE)
6392 LOGE("failed to get gapless mode");
6394 /* check repeat count in case of audio */
6396 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6397 LOGW("gapless is disabled");
6401 num_of_uri = g_list_length(player->uri_info.uri_list);
6403 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6405 if (num_of_uri == ORIGINAL_URI_ONLY) {
6406 /* audio looping path */
6407 if (count >= REPEAT_COUNT_MIN) {
6408 /* decrease play count */
6409 /* we succeeded to rewind. update play count and then wait for next EOS */
6411 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6412 /* commit attribute */
6413 if (mm_attrs_commit_all(attrs))
6414 LOGE("failed to commit attribute");
6416 } else if (count != REPEAT_COUNT_INFINITE) {
6417 LOGD("there is no next uri and no repeat");
6420 LOGD("looping cnt %d", count);
6422 /* gapless playback path */
6423 if (!__mmplayer_get_next_uri(player)) {
6424 LOGE("failed to get next uri");
6431 LOGE("unable to play gapless path. EOS will be posted soon");
6436 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6438 mmplayer_selector_t *selector = &player->selector[type];
6439 mmplayer_gst_element_t *sinkbin = NULL;
6440 main_element_id_e selectorId = MMPLAYER_M_NUM;
6441 main_element_id_e sinkId = MMPLAYER_M_NUM;
6442 GstPad *srcpad = NULL;
6443 GstPad *sinkpad = NULL;
6444 gboolean send_notice = FALSE;
6447 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6449 LOGD("type %d", type);
6452 case MM_PLAYER_TRACK_TYPE_AUDIO:
6453 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6454 sinkId = MMPLAYER_A_BIN;
6455 sinkbin = player->pipeline->audiobin;
6457 case MM_PLAYER_TRACK_TYPE_VIDEO:
6458 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6459 sinkId = MMPLAYER_V_BIN;
6460 sinkbin = player->pipeline->videobin;
6463 case MM_PLAYER_TRACK_TYPE_TEXT:
6464 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6465 sinkId = MMPLAYER_T_BIN;
6466 sinkbin = player->pipeline->textbin;
6469 LOGE("requested type is not supportable");
6474 if (player->pipeline->mainbin[selectorId].gst) {
6477 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6479 if (selector->event_probe_id != 0)
6480 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6481 selector->event_probe_id = 0;
6483 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6484 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6486 if (srcpad && sinkpad) {
6487 /* after getting drained signal there is no data flows, so no need to do pad_block */
6488 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6489 gst_pad_unlink(srcpad, sinkpad);
6491 /* send custom event to sink pad to handle it at video sink */
6493 LOGD("send custom event to sinkpad");
6494 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6495 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6496 gst_pad_send_event(sinkpad, event);
6500 gst_object_unref(sinkpad);
6503 gst_object_unref(srcpad);
6506 LOGD("selector release");
6508 /* release and unref requests pad from the selector */
6509 for (n = 0; n < selector->channels->len; n++) {
6510 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6511 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6513 g_ptr_array_set_size(selector->channels, 0);
6515 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6516 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6518 player->pipeline->mainbin[selectorId].gst = NULL;
6526 __mmplayer_deactivate_old_path(mmplayer_t *player)
6529 MMPLAYER_RETURN_IF_FAIL(player);
6531 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6532 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6533 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6534 LOGE("deactivate selector error");
6538 _mmplayer_track_destroy(player);
6539 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6541 if (player->streamer) {
6542 _mm_player_streaming_initialize(player->streamer, FALSE);
6543 _mm_player_streaming_destroy(player->streamer);
6544 player->streamer = NULL;
6547 MMPLAYER_PLAYBACK_LOCK(player);
6548 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6555 if (!player->msg_posted) {
6556 MMMessageParamType msg = {0,};
6559 msg.code = MM_ERROR_PLAYER_INTERNAL;
6560 LOGE("gapless_uri_play> deactivate error");
6562 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6563 player->msg_posted = TRUE;
6569 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6571 int result = MM_ERROR_NONE;
6572 mmplayer_t *player = (mmplayer_t *)hplayer;
6575 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6577 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6578 if (mm_attrs_commit_all(player->attrs)) {
6579 LOGE("failed to commit the original uri.");
6580 result = MM_ERROR_PLAYER_INTERNAL;
6582 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6583 LOGE("failed to add the original uri in the uri list.");
6591 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6593 mmplayer_t *player = (mmplayer_t *)hplayer;
6594 guint num_of_list = 0;
6598 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6599 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6601 if (player->pipeline && player->pipeline->textbin) {
6602 LOGE("subtitle path is enabled.");
6603 return MM_ERROR_PLAYER_INVALID_STATE;
6606 num_of_list = g_list_length(player->uri_info.uri_list);
6608 if (is_first_path) {
6609 if (num_of_list == 0) {
6610 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6611 SECURE_LOGD("add original path : %s", uri);
6613 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6614 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6616 SECURE_LOGD("change original path : %s", uri);
6619 MMHandleType attrs = 0;
6620 attrs = MMPLAYER_GET_ATTRS(player);
6622 if (num_of_list == 0) {
6623 char *original_uri = NULL;
6626 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6628 if (!original_uri) {
6629 LOGE("there is no original uri.");
6630 return MM_ERROR_PLAYER_INVALID_STATE;
6633 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6634 player->uri_info.uri_idx = 0;
6636 SECURE_LOGD("add original path at first : %s", original_uri);
6640 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6641 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6645 return MM_ERROR_NONE;
6649 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6651 mmplayer_t *player = (mmplayer_t *)hplayer;
6652 char *next_uri = NULL;
6653 guint num_of_list = 0;
6656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6658 num_of_list = g_list_length(player->uri_info.uri_list);
6660 if (num_of_list > 0) {
6661 gint uri_idx = player->uri_info.uri_idx;
6663 if (uri_idx < num_of_list-1)
6668 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6669 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6671 *uri = g_strdup(next_uri);
6675 return MM_ERROR_NONE;
6679 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6680 GstCaps *caps, gpointer data)
6682 mmplayer_t *player = (mmplayer_t *)data;
6683 const gchar *klass = NULL;
6684 const gchar *mime = NULL;
6685 gchar *caps_str = NULL;
6687 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6688 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6689 caps_str = gst_caps_to_string(caps);
6691 LOGW("unknown type of caps : %s from %s",
6692 caps_str, GST_ELEMENT_NAME(elem));
6694 MMPLAYER_FREEIF(caps_str);
6696 /* There is no available codec. */
6697 __mmplayer_check_not_supported_codec(player, klass, mime);
6701 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6702 GstCaps *caps, gpointer data)
6704 mmplayer_t *player = (mmplayer_t *)data;
6705 const char *mime = NULL;
6706 gboolean ret = TRUE;
6708 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6709 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6711 if (g_str_has_prefix(mime, "audio")) {
6712 GstStructure *caps_structure = NULL;
6713 gint samplerate = 0;
6715 gchar *caps_str = NULL;
6717 caps_structure = gst_caps_get_structure(caps, 0);
6718 gst_structure_get_int(caps_structure, "rate", &samplerate);
6719 gst_structure_get_int(caps_structure, "channels", &channels);
6721 if ((channels > 0 && samplerate == 0)) {
6722 LOGD("exclude audio...");
6726 caps_str = gst_caps_to_string(caps);
6727 /* set it directly because not sent by TAG */
6728 if (g_strrstr(caps_str, "mobile-xmf"))
6729 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6730 MMPLAYER_FREEIF(caps_str);
6731 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6732 MMMessageParamType msg_param;
6733 memset(&msg_param, 0, sizeof(MMMessageParamType));
6734 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6735 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6736 LOGD("video file is not supported on this device");
6738 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6739 LOGD("already video linked");
6742 LOGD("found new stream");
6749 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6751 gboolean ret = TRUE;
6752 GDBusConnection *conn = NULL;
6754 GVariant *result = NULL;
6755 const gchar *dbus_device_type = NULL;
6756 const gchar *dbus_ret = NULL;
6759 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6761 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6767 result = g_dbus_connection_call_sync(conn,
6768 "org.pulseaudio.Server",
6769 "/org/pulseaudio/StreamManager",
6770 "org.pulseaudio.StreamManager",
6771 "GetCurrentMediaRoutingPath",
6772 g_variant_new("(s)", "out"),
6773 G_VARIANT_TYPE("(ss)"),
6774 G_DBUS_CALL_FLAGS_NONE,
6778 if (!result || err) {
6779 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6785 /* device type is listed in stream-map.json at mmfw-sysconf */
6786 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6788 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6789 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6794 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6795 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6796 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6797 LOGD("audio offload is supportable");
6803 LOGD("audio offload is not supportable");
6807 g_variant_unref(result);
6808 g_object_unref(conn);
6813 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6815 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6816 gint64 position = 0;
6818 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6819 player->pipeline && player->pipeline->mainbin);
6821 MMPLAYER_CMD_LOCK(player);
6822 current_state = MMPLAYER_CURRENT_STATE(player);
6824 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6825 LOGW("getting current position failed in paused");
6827 _mmplayer_unrealize((MMHandleType)player);
6828 _mmplayer_realize((MMHandleType)player);
6830 _mmplayer_set_position((MMHandleType)player, position);
6832 /* async not to be blocked in streaming case */
6833 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6834 if (mm_attrs_commit_all(player->attrs))
6835 LOGE("failed to commit");
6837 _mmplayer_pause((MMHandleType)player);
6839 if (current_state == MM_PLAYER_STATE_PLAYING)
6840 _mmplayer_start((MMHandleType)player);
6841 MMPLAYER_CMD_UNLOCK(player);
6843 LOGD("rebuilding audio pipeline is completed.");
6846 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6848 mmplayer_t *player = (mmplayer_t *)user_data;
6849 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6850 gboolean is_supportable = FALSE;
6852 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6853 LOGW("failed to get device type");
6855 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6857 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6858 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6859 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6860 LOGD("ignore this dev connected info");
6864 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6865 if (player->build_audio_offload == is_supportable) {
6866 LOGD("keep current pipeline without re-building");
6870 /* rebuild pipeline */
6871 LOGD("re-build pipeline - offload: %d", is_supportable);
6872 player->build_audio_offload = FALSE;
6873 __mmplayer_rebuild_audio_pipeline(player);
6879 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6881 unsigned int id = 0;
6883 if (player->audio_device_cb_id != 0) {
6884 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6888 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6889 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6890 LOGD("added device connected cb (%u)", id);
6891 player->audio_device_cb_id = id;
6893 LOGW("failed to add device connected cb");
6901 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6903 gboolean ret = FALSE;
6904 GstElementFactory *factory = NULL;
6907 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6909 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6910 if (!__mmplayer_is_only_mp3_type(player->type))
6913 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6914 LOGD("there is no audio offload sink");
6918 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6919 LOGW("there is no audio device type to support offload");
6923 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6925 LOGW("there is no installed audio offload sink element");
6928 gst_object_unref(factory);
6930 if (__mmplayer_acquire_hw_resource(player,
6931 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6932 LOGE("failed to acquire audio offload decoder resource");
6936 if (!__mmplayer_add_audio_device_connected_cb(player))
6939 if (!__mmplayer_is_audio_offload_device_type(player))
6942 LOGD("audio offload can be built");
6947 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6953 static GstAutoplugSelectResult
6954 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6956 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6958 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6959 int audio_offload = 0;
6961 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6962 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6964 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6965 LOGD("expose audio path to build offload output path");
6966 player->build_audio_offload = TRUE;
6967 /* update codec info */
6968 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6969 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6970 player->audiodec_linked = 1;
6972 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6976 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6978 LOGD("audio codec type: %d", codec_type);
6979 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6980 /* sw codec will be skipped */
6981 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6982 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6983 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6984 ret = GST_AUTOPLUG_SELECT_SKIP;
6988 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6989 /* hw codec will be skipped */
6990 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6991 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6992 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6993 ret = GST_AUTOPLUG_SELECT_SKIP;
6998 /* set stream information */
6999 if (!player->audiodec_linked)
7000 __mmplayer_set_audio_attrs(player, caps);
7002 /* update codec info */
7003 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7004 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7005 player->audiodec_linked = 1;
7007 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7009 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7011 LOGD("video codec type: %d", codec_type);
7012 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7013 /* sw codec is skipped */
7014 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7015 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7016 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7017 ret = GST_AUTOPLUG_SELECT_SKIP;
7021 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7022 /* hw codec is skipped */
7023 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7024 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7025 ret = GST_AUTOPLUG_SELECT_SKIP;
7030 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7031 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7033 /* mark video decoder for acquire */
7034 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7035 LOGW("video decoder resource is already acquired, skip it.");
7036 ret = GST_AUTOPLUG_SELECT_SKIP;
7040 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7041 LOGE("failed to acquire video decoder resource");
7042 ret = GST_AUTOPLUG_SELECT_SKIP;
7045 player->interrupted_by_resource = FALSE;
7048 /* update codec info */
7049 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7050 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7051 player->videodec_linked = 1;
7059 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7060 GstCaps *caps, GstElementFactory *factory, gpointer data)
7062 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7063 mmplayer_t *player = (mmplayer_t *)data;
7065 gchar *factory_name = NULL;
7066 gchar *caps_str = NULL;
7067 const gchar *klass = NULL;
7070 factory_name = GST_OBJECT_NAME(factory);
7071 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7072 caps_str = gst_caps_to_string(caps);
7074 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7076 /* store type string */
7077 if (player->type == NULL) {
7078 player->type = gst_caps_to_string(caps);
7079 __mmplayer_update_content_type_info(player);
7082 /* filtering exclude keyword */
7083 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7084 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7085 LOGW("skipping [%s] by exculde keyword [%s]",
7086 factory_name, player->ini.exclude_element_keyword[idx]);
7088 result = GST_AUTOPLUG_SELECT_SKIP;
7093 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7094 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7095 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7096 factory_name, player->ini.unsupported_codec_keyword[idx]);
7097 result = GST_AUTOPLUG_SELECT_SKIP;
7102 /* exclude webm format */
7103 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7104 * because webm format is not supportable.
7105 * If webm is disabled in "autoplug-continue", there is no state change
7106 * failure or error because the decodebin will expose the pad directly.
7107 * It make MSL invoke _prepare_async_callback.
7108 * So, we need to disable webm format in "autoplug-select" */
7109 if (caps_str && strstr(caps_str, "webm")) {
7110 LOGW("webm is not supported");
7111 result = GST_AUTOPLUG_SELECT_SKIP;
7115 /* check factory class for filtering */
7116 /* NOTE : msl don't need to use image plugins.
7117 * So, those plugins should be skipped for error handling.
7119 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7120 LOGD("skipping [%s] by not required", factory_name);
7121 result = GST_AUTOPLUG_SELECT_SKIP;
7125 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7126 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7127 // TO CHECK : subtitle if needed, add subparse exception.
7128 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7129 result = GST_AUTOPLUG_SELECT_SKIP;
7133 if (g_strrstr(factory_name, "mpegpsdemux")) {
7134 LOGD("skipping PS container - not support");
7135 result = GST_AUTOPLUG_SELECT_SKIP;
7139 if (g_strrstr(factory_name, "mssdemux"))
7140 player->smooth_streaming = TRUE;
7142 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7143 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7146 GstStructure *str = NULL;
7147 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7149 /* don't make video because of not required */
7150 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7151 (!player->set_mode.video_export)) {
7152 LOGD("no need video decoding, expose pad");
7153 result = GST_AUTOPLUG_SELECT_EXPOSE;
7157 /* get w/h for omx state-tune */
7158 /* FIXME: deprecated? */
7159 str = gst_caps_get_structure(caps, 0);
7160 gst_structure_get_int(str, "width", &width);
7163 if (player->v_stream_caps) {
7164 gst_caps_unref(player->v_stream_caps);
7165 player->v_stream_caps = NULL;
7168 player->v_stream_caps = gst_caps_copy(caps);
7169 LOGD("take caps for video state tune");
7170 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7174 if (g_strrstr(klass, "Codec/Decoder")) {
7175 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7176 if (result != GST_AUTOPLUG_SELECT_TRY) {
7177 LOGW("skip add decoder");
7183 MMPLAYER_FREEIF(caps_str);
7189 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7192 //mmplayer_t *player = (mmplayer_t *)data;
7193 GstCaps *caps = NULL;
7195 LOGD("[Decodebin2] pad-removed signal");
7197 caps = gst_pad_query_caps(new_pad, NULL);
7199 LOGW("query caps is NULL");
7203 gchar *caps_str = NULL;
7204 caps_str = gst_caps_to_string(caps);
7206 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7208 MMPLAYER_FREEIF(caps_str);
7209 gst_caps_unref(caps);
7213 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7215 mmplayer_t *player = (mmplayer_t *)data;
7216 GstIterator *iter = NULL;
7217 GValue item = { 0, };
7219 gboolean done = FALSE;
7220 gboolean is_all_drained = TRUE;
7223 MMPLAYER_RETURN_IF_FAIL(player);
7225 LOGD("__mmplayer_gst_decode_drained");
7227 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7228 LOGW("Fail to get cmd lock");
7232 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7233 !__mmplayer_verify_gapless_play_path(player)) {
7234 LOGD("decoding is finished.");
7235 __mmplayer_reset_gapless_state(player);
7236 MMPLAYER_CMD_UNLOCK(player);
7240 player->gapless.reconfigure = TRUE;
7242 /* check decodebin src pads whether they received EOS or not */
7243 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7246 switch (gst_iterator_next(iter, &item)) {
7247 case GST_ITERATOR_OK:
7248 pad = g_value_get_object(&item);
7249 if (pad && !GST_PAD_IS_EOS(pad)) {
7250 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7251 is_all_drained = FALSE;
7254 g_value_reset(&item);
7256 case GST_ITERATOR_RESYNC:
7257 gst_iterator_resync(iter);
7259 case GST_ITERATOR_ERROR:
7260 case GST_ITERATOR_DONE:
7265 g_value_unset(&item);
7266 gst_iterator_free(iter);
7268 if (!is_all_drained) {
7269 LOGD("Wait util the all pads get EOS.");
7270 MMPLAYER_CMD_UNLOCK(player);
7275 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7276 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7278 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7279 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7280 __mmplayer_deactivate_old_path(player);
7281 MMPLAYER_CMD_UNLOCK(player);
7287 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7289 mmplayer_t *player = (mmplayer_t *)data;
7290 const gchar *klass = NULL;
7291 gchar *factory_name = NULL;
7293 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7294 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7296 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7298 if (__mmplayer_add_dump_buffer_probe(player, element))
7299 LOGD("add buffer probe");
7301 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7302 gchar *selected = NULL;
7303 selected = g_strdup(GST_ELEMENT_NAME(element));
7304 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7307 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7308 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7309 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7311 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7312 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7314 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7315 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7316 "max-video-width", player->adaptive_info.limit.width,
7317 "max-video-height", player->adaptive_info.limit.height, NULL);
7319 } else if (g_strrstr(klass, "Demuxer")) {
7321 LOGD("plugged element is demuxer. take it");
7323 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7324 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7327 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7328 int surface_type = 0;
7330 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7333 // to support trust-zone only
7334 if (g_strrstr(factory_name, "asfdemux")) {
7335 LOGD("set file-location %s", player->profile.uri);
7336 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7337 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7338 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7339 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7340 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7341 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7342 (__mmplayer_is_only_mp3_type(player->type))) {
7343 LOGD("[mpegaudioparse] set streaming pull mode.");
7344 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7346 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7347 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7350 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7351 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7352 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7354 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7355 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7357 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7358 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7359 (MMPLAYER_IS_DASH_STREAMING(player))) {
7360 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7361 _mm_player_streaming_set_multiqueue(player->streamer, element);
7362 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7371 __mmplayer_release_misc(mmplayer_t *player)
7374 bool cur_mode = player->set_mode.rich_audio;
7377 MMPLAYER_RETURN_IF_FAIL(player);
7379 player->video_decoded_cb = NULL;
7380 player->video_decoded_cb_user_param = NULL;
7381 player->video_stream_prerolled = false;
7383 player->audio_decoded_cb = NULL;
7384 player->audio_decoded_cb_user_param = NULL;
7385 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7387 player->audio_stream_changed_cb = NULL;
7388 player->audio_stream_changed_cb_user_param = NULL;
7390 player->sent_bos = FALSE;
7391 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7393 player->seek_state = MMPLAYER_SEEK_NONE;
7395 player->total_bitrate = 0;
7396 player->total_maximum_bitrate = 0;
7398 player->not_found_demuxer = 0;
7400 player->last_position = 0;
7401 player->duration = 0;
7402 player->http_content_size = 0;
7403 player->not_supported_codec = MISSING_PLUGIN_NONE;
7404 player->can_support_codec = FOUND_PLUGIN_NONE;
7405 player->pending_seek.is_pending = false;
7406 player->pending_seek.pos = 0;
7407 player->msg_posted = FALSE;
7408 player->has_many_types = FALSE;
7409 player->is_subtitle_force_drop = FALSE;
7410 player->play_subtitle = FALSE;
7411 player->adjust_subtitle_pos = 0;
7412 player->has_closed_caption = FALSE;
7413 player->set_mode.video_export = false;
7414 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7415 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7417 player->set_mode.rich_audio = cur_mode;
7419 if (player->audio_device_cb_id > 0 &&
7420 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7421 LOGW("failed to remove audio device_connected_callback");
7422 player->audio_device_cb_id = 0;
7424 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7425 player->bitrate[i] = 0;
7426 player->maximum_bitrate[i] = 0;
7429 /* free memory related to audio effect */
7430 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7432 if (player->adaptive_info.var_list) {
7433 g_list_free_full(player->adaptive_info.var_list, g_free);
7434 player->adaptive_info.var_list = NULL;
7437 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7438 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7439 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7441 /* Reset video360 settings to their defaults in case if the pipeline is to be
7444 player->video360_metadata.is_spherical = -1;
7445 player->is_openal_plugin_used = FALSE;
7447 player->is_content_spherical = FALSE;
7448 player->is_video360_enabled = TRUE;
7449 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7450 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7451 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7452 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7453 player->video360_zoom = 1.0f;
7454 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7455 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7457 player->sound.rg_enable = false;
7459 __mmplayer_initialize_video_roi(player);
7464 __mmplayer_release_misc_post(mmplayer_t *player)
7466 char *original_uri = NULL;
7469 /* player->pipeline is already released before. */
7471 MMPLAYER_RETURN_IF_FAIL(player);
7473 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7475 /* clean found audio decoders */
7476 if (player->audio_decoders) {
7477 GList *a_dec = player->audio_decoders;
7478 for (; a_dec; a_dec = g_list_next(a_dec)) {
7479 gchar *name = a_dec->data;
7480 MMPLAYER_FREEIF(name);
7482 g_list_free(player->audio_decoders);
7483 player->audio_decoders = NULL;
7486 /* clean the uri list except original uri */
7487 if (player->uri_info.uri_list) {
7488 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7490 if (player->attrs) {
7491 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7492 LOGD("restore original uri = %s", original_uri);
7494 if (mm_attrs_commit_all(player->attrs))
7495 LOGE("failed to commit the original uri.");
7498 GList *uri_list = player->uri_info.uri_list;
7499 for (; uri_list; uri_list = g_list_next(uri_list)) {
7500 gchar *uri = uri_list->data;
7501 MMPLAYER_FREEIF(uri);
7503 g_list_free(player->uri_info.uri_list);
7504 player->uri_info.uri_list = NULL;
7507 /* clear the audio stream buffer list */
7508 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7510 /* clear the video stream bo list */
7511 __mmplayer_video_stream_destroy_bo_list(player);
7512 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7514 if (player->profile.input_mem.buf) {
7515 free(player->profile.input_mem.buf);
7516 player->profile.input_mem.buf = NULL;
7518 player->profile.input_mem.len = 0;
7519 player->profile.input_mem.offset = 0;
7521 player->uri_info.uri_idx = 0;
7526 __mmplayer_check_subtitle(mmplayer_t *player)
7528 MMHandleType attrs = 0;
7529 char *subtitle_uri = NULL;
7533 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7535 /* get subtitle attribute */
7536 attrs = MMPLAYER_GET_ATTRS(player);
7540 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7541 if (!subtitle_uri || !strlen(subtitle_uri))
7544 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7545 player->is_external_subtitle_present = TRUE;
7553 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7555 MMPLAYER_RETURN_IF_FAIL(player);
7557 if (player->eos_timer) {
7558 LOGD("cancel eos timer");
7559 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7560 player->eos_timer = 0;
7567 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7571 MMPLAYER_RETURN_IF_FAIL(player);
7572 MMPLAYER_RETURN_IF_FAIL(sink);
7574 player->sink_elements = g_list_append(player->sink_elements, sink);
7580 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7584 MMPLAYER_RETURN_IF_FAIL(player);
7585 MMPLAYER_RETURN_IF_FAIL(sink);
7587 player->sink_elements = g_list_remove(player->sink_elements, sink);
7593 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7594 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7596 mmplayer_signal_item_t *item = NULL;
7599 MMPLAYER_RETURN_IF_FAIL(player);
7601 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7602 LOGE("invalid signal type [%d]", type);
7606 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7608 LOGE("cannot connect signal [%s]", signal);
7613 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7614 player->signals[type] = g_list_append(player->signals[type], item);
7620 /* NOTE : be careful with calling this api. please refer to below glib comment
7621 * glib comment : Note that there is a bug in GObject that makes this function much
7622 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7623 * will no longer be called, but, the signal handler is not currently disconnected.
7624 * If the instance is itself being freed at the same time than this doesn't matter,
7625 * since the signal will automatically be removed, but if instance persists,
7626 * then the signal handler will leak. You should not remove the signal yourself
7627 * because in a future versions of GObject, the handler will automatically be
7630 * It's possible to work around this problem in a way that will continue to work
7631 * with future versions of GObject by checking that the signal handler is still
7632 * connected before disconnected it:
7634 * if (g_signal_handler_is_connected(instance, id))
7635 * g_signal_handler_disconnect(instance, id);
7638 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7640 GList *sig_list = NULL;
7641 mmplayer_signal_item_t *item = NULL;
7645 MMPLAYER_RETURN_IF_FAIL(player);
7647 LOGD("release signals type : %d", type);
7649 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7650 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7651 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7652 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7653 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7654 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7658 sig_list = player->signals[type];
7660 for (; sig_list; sig_list = sig_list->next) {
7661 item = sig_list->data;
7663 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7664 if (g_signal_handler_is_connected(item->obj, item->sig))
7665 g_signal_handler_disconnect(item->obj, item->sig);
7668 MMPLAYER_FREEIF(item);
7671 g_list_free(player->signals[type]);
7672 player->signals[type] = NULL;
7680 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7682 mmplayer_t *player = 0;
7683 int prev_display_surface_type = 0;
7684 void *prev_display_overlay = NULL;
7688 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7689 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7691 player = MM_PLAYER_CAST(handle);
7693 /* check video sinkbin is created */
7694 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7695 LOGW("Videosink is already created");
7696 return MM_ERROR_NONE;
7699 LOGD("videosink element is not yet ready");
7701 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7702 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7704 return MM_ERROR_INVALID_ARGUMENT;
7707 /* load previous attributes */
7708 if (player->attrs) {
7709 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7710 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7711 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7712 if (prev_display_surface_type == surface_type) {
7713 LOGD("incoming display surface type is same as previous one, do nothing..");
7715 return MM_ERROR_NONE;
7718 LOGE("failed to load attributes");
7720 return MM_ERROR_PLAYER_INTERNAL;
7723 /* videobin is not created yet, so we just set attributes related to display surface */
7724 LOGD("store display attribute for given surface type(%d)", surface_type);
7725 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7726 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7727 if (mm_attrs_commit_all(player->attrs)) {
7728 LOGE("failed to commit attribute");
7730 return MM_ERROR_PLAYER_INTERNAL;
7734 return MM_ERROR_NONE;
7737 /* Note : if silent is true, then subtitle would not be displayed. :*/
7739 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7741 mmplayer_t *player = (mmplayer_t *)hplayer;
7745 /* check player handle */
7746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7748 player->set_mode.subtitle_off = silent;
7750 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7754 return MM_ERROR_NONE;
7758 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7760 mmplayer_gst_element_t *mainbin = NULL;
7761 mmplayer_gst_element_t *textbin = NULL;
7762 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7763 GstState current_state = GST_STATE_VOID_PENDING;
7764 GstState element_state = GST_STATE_VOID_PENDING;
7765 GstState element_pending_state = GST_STATE_VOID_PENDING;
7767 GstEvent *event = NULL;
7768 int result = MM_ERROR_NONE;
7770 GstClock *curr_clock = NULL;
7771 GstClockTime base_time, start_time, curr_time;
7776 /* check player handle */
7777 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7779 player->pipeline->mainbin &&
7780 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7782 mainbin = player->pipeline->mainbin;
7783 textbin = player->pipeline->textbin;
7785 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7787 // sync clock with current pipeline
7788 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7789 curr_time = gst_clock_get_time(curr_clock);
7791 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7792 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7794 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7795 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7797 if (current_state > GST_STATE_READY) {
7798 // sync state with current pipeline
7799 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7800 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7801 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7803 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7804 if (GST_STATE_CHANGE_FAILURE == ret) {
7805 LOGE("fail to state change.");
7806 result = MM_ERROR_PLAYER_INTERNAL;
7810 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7811 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7814 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7815 gst_object_unref(curr_clock);
7818 // seek to current position
7819 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7820 result = MM_ERROR_PLAYER_INVALID_STATE;
7821 LOGE("gst_element_query_position failed, invalid state");
7825 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7826 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);
7828 _mmplayer_gst_send_event_to_sink(player, event);
7830 result = MM_ERROR_PLAYER_INTERNAL;
7831 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7835 /* sync state with current pipeline */
7836 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7837 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7838 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7840 return MM_ERROR_NONE;
7843 /* release text pipeline resource */
7844 player->textsink_linked = 0;
7846 /* release signal */
7847 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7849 /* release textbin with it's childs */
7850 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7851 MMPLAYER_FREEIF(player->pipeline->textbin);
7852 player->pipeline->textbin = NULL;
7854 /* release subtitle elem */
7855 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7856 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7862 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7864 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7865 GstState current_state = GST_STATE_VOID_PENDING;
7867 MMHandleType attrs = 0;
7868 mmplayer_gst_element_t *mainbin = NULL;
7869 mmplayer_gst_element_t *textbin = NULL;
7871 gchar *subtitle_uri = NULL;
7872 int result = MM_ERROR_NONE;
7873 const gchar *charset = NULL;
7877 /* check player handle */
7878 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7880 player->pipeline->mainbin &&
7881 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7882 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7884 mainbin = player->pipeline->mainbin;
7885 textbin = player->pipeline->textbin;
7887 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7888 if (current_state < GST_STATE_READY) {
7889 result = MM_ERROR_PLAYER_INVALID_STATE;
7890 LOGE("Pipeline is not in proper state");
7894 attrs = MMPLAYER_GET_ATTRS(player);
7896 LOGE("cannot get content attribute");
7897 result = MM_ERROR_PLAYER_INTERNAL;
7901 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7902 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7903 LOGE("subtitle uri is not proper filepath");
7904 result = MM_ERROR_PLAYER_INVALID_URI;
7908 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7909 LOGE("failed to get storage info of subtitle path");
7910 result = MM_ERROR_PLAYER_INVALID_URI;
7914 LOGD("old subtitle file path is [%s]", subtitle_uri);
7915 LOGD("new subtitle file path is [%s]", filepath);
7917 if (!strcmp(filepath, subtitle_uri)) {
7918 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7921 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7922 if (mm_attrs_commit_all(player->attrs)) {
7923 LOGE("failed to commit.");
7928 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7929 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7930 player->subtitle_language_list = NULL;
7931 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7933 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7934 if (ret != GST_STATE_CHANGE_SUCCESS) {
7935 LOGE("failed to change state of textbin to READY");
7936 result = MM_ERROR_PLAYER_INTERNAL;
7940 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7941 if (ret != GST_STATE_CHANGE_SUCCESS) {
7942 LOGE("failed to change state of subparse to READY");
7943 result = MM_ERROR_PLAYER_INTERNAL;
7947 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7948 if (ret != GST_STATE_CHANGE_SUCCESS) {
7949 LOGE("failed to change state of filesrc to READY");
7950 result = MM_ERROR_PLAYER_INTERNAL;
7954 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7956 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7958 charset = _mmplayer_get_charset(filepath);
7960 LOGD("detected charset is %s", charset);
7961 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7964 result = _mmplayer_sync_subtitle_pipeline(player);
7971 /* API to switch between external subtitles */
7973 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7975 int result = MM_ERROR_NONE;
7976 mmplayer_t *player = (mmplayer_t *)hplayer;
7981 /* check player handle */
7982 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7984 /* filepath can be null in idle state */
7986 /* check file path */
7987 if ((path = strstr(filepath, "file://")))
7988 result = _mmplayer_exist_file_path(path + 7);
7990 result = _mmplayer_exist_file_path(filepath);
7992 if (result != MM_ERROR_NONE) {
7993 LOGE("invalid subtitle path 0x%X", result);
7994 return result; /* file not found or permission denied */
7998 if (!player->pipeline) {
8000 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8001 if (mm_attrs_commit_all(player->attrs)) {
8002 LOGE("failed to commit"); /* subtitle path will not be created */
8003 return MM_ERROR_PLAYER_INTERNAL;
8006 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8007 /* check filepath */
8008 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8010 if (!__mmplayer_check_subtitle(player)) {
8011 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8012 if (mm_attrs_commit_all(player->attrs)) {
8013 LOGE("failed to commit");
8014 return MM_ERROR_PLAYER_INTERNAL;
8017 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8018 LOGE("fail to create text pipeline");
8019 return MM_ERROR_PLAYER_INTERNAL;
8022 result = _mmplayer_sync_subtitle_pipeline(player);
8024 result = __mmplayer_change_external_subtitle_language(player, filepath);
8027 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8028 player->is_external_subtitle_added_now = TRUE;
8030 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8031 if (!player->subtitle_language_list) {
8032 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8033 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8034 LOGW("subtitle language list is not updated yet");
8036 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8044 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8046 int result = MM_ERROR_NONE;
8047 gchar *change_pad_name = NULL;
8048 GstPad *sinkpad = NULL;
8049 mmplayer_gst_element_t *mainbin = NULL;
8050 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8051 GstCaps *caps = NULL;
8052 gint total_track_num = 0;
8056 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8057 MM_ERROR_PLAYER_NOT_INITIALIZED);
8059 LOGD("Change Track(%d) to %d", type, index);
8061 mainbin = player->pipeline->mainbin;
8063 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8064 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8065 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8066 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8068 /* Changing Video Track is not supported. */
8069 LOGE("Track Type Error");
8073 if (mainbin[elem_idx].gst == NULL) {
8074 result = MM_ERROR_PLAYER_NO_OP;
8075 LOGD("Req track doesn't exist");
8079 total_track_num = player->selector[type].total_track_num;
8080 if (total_track_num <= 0) {
8081 result = MM_ERROR_PLAYER_NO_OP;
8082 LOGD("Language list is not available");
8086 if ((index < 0) || (index >= total_track_num)) {
8087 result = MM_ERROR_INVALID_ARGUMENT;
8088 LOGD("Not a proper index : %d", index);
8092 /*To get the new pad from the selector*/
8093 change_pad_name = g_strdup_printf("sink_%u", index);
8094 if (change_pad_name == NULL) {
8095 result = MM_ERROR_PLAYER_INTERNAL;
8096 LOGD("Pad does not exists");
8100 LOGD("new active pad name: %s", change_pad_name);
8102 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8103 if (sinkpad == NULL) {
8104 LOGD("sinkpad is NULL");
8105 result = MM_ERROR_PLAYER_INTERNAL;
8109 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8110 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8112 caps = gst_pad_get_current_caps(sinkpad);
8113 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8116 gst_object_unref(sinkpad);
8118 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8119 __mmplayer_set_audio_attrs(player, caps);
8122 MMPLAYER_FREEIF(change_pad_name);
8127 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8129 int result = MM_ERROR_NONE;
8130 mmplayer_t *player = NULL;
8131 mmplayer_gst_element_t *mainbin = NULL;
8133 gint current_active_index = 0;
8135 GstState current_state = GST_STATE_VOID_PENDING;
8136 GstEvent *event = NULL;
8141 player = (mmplayer_t *)hplayer;
8142 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8144 if (!player->pipeline) {
8145 LOGE("Track %d pre setting -> %d", type, index);
8147 player->selector[type].active_pad_index = index;
8151 mainbin = player->pipeline->mainbin;
8153 current_active_index = player->selector[type].active_pad_index;
8155 /*If index is same as running index no need to change the pad*/
8156 if (current_active_index == index)
8159 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8160 result = MM_ERROR_PLAYER_INVALID_STATE;
8164 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8165 if (current_state < GST_STATE_PAUSED) {
8166 result = MM_ERROR_PLAYER_INVALID_STATE;
8167 LOGW("Pipeline not in porper state");
8171 result = __mmplayer_change_selector_pad(player, type, index);
8172 if (result != MM_ERROR_NONE) {
8173 LOGE("change selector pad error");
8177 player->selector[type].active_pad_index = index;
8179 if (current_state == GST_STATE_PLAYING) {
8180 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8181 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8182 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8184 _mmplayer_gst_send_event_to_sink(player, event);
8186 result = MM_ERROR_PLAYER_INTERNAL;
8196 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8198 mmplayer_t *player = (mmplayer_t *)hplayer;
8202 /* check player handle */
8203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8205 *silent = player->set_mode.subtitle_off;
8207 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8211 return MM_ERROR_NONE;
8215 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8217 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8218 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8220 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8221 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8225 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8226 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8227 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8228 mmplayer_dump_t *dump_s;
8229 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8230 if (dump_s == NULL) {
8231 LOGE("malloc fail");
8235 dump_s->dump_element_file = NULL;
8236 dump_s->dump_pad = NULL;
8237 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8239 if (dump_s->dump_pad) {
8240 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8241 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]);
8242 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8243 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);
8244 /* add list for removed buffer probe and close FILE */
8245 player->dump_list = g_list_append(player->dump_list, dump_s);
8246 LOGD("%s sink pad added buffer probe for dump", factory_name);
8249 MMPLAYER_FREEIF(dump_s);
8250 LOGE("failed to get %s sink pad added", factory_name);
8257 static GstPadProbeReturn
8258 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8260 FILE *dump_data = (FILE *)u_data;
8262 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8263 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8265 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8267 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8269 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8271 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8273 gst_buffer_unmap(buffer, &probe_info);
8275 return GST_PAD_PROBE_OK;
8279 __mmplayer_release_dump_list(GList *dump_list)
8281 GList *d_list = dump_list;
8286 for (; d_list; d_list = g_list_next(d_list)) {
8287 mmplayer_dump_t *dump_s = d_list->data;
8288 if (dump_s->dump_pad) {
8289 if (dump_s->probe_handle_id)
8290 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8291 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8293 if (dump_s->dump_element_file) {
8294 fclose(dump_s->dump_element_file);
8295 dump_s->dump_element_file = NULL;
8297 MMPLAYER_FREEIF(dump_s);
8299 g_list_free(dump_list);
8304 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8306 mmplayer_t *player = (mmplayer_t *)hplayer;
8310 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8311 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8313 *exist = (bool)player->has_closed_caption;
8317 return MM_ERROR_NONE;
8321 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8326 LOGD("unref internal gst buffer %p", buffer);
8328 gst_buffer_unref((GstBuffer *)buffer);
8335 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8337 mmplayer_t *player = (mmplayer_t *)hplayer;
8341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8342 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8344 if (MMPLAYER_IS_STREAMING(player))
8345 *timeout = (int)player->ini.live_state_change_timeout;
8347 *timeout = (int)player->ini.localplayback_state_change_timeout;
8349 LOGD("timeout = %d", *timeout);
8352 return MM_ERROR_NONE;
8356 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8360 MMPLAYER_RETURN_IF_FAIL(player);
8362 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8364 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8365 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8366 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8367 player->storage_info[i].id = -1;
8368 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8370 if (path_type != MMPLAYER_PATH_MAX)
8379 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8381 int ret = MM_ERROR_NONE;
8382 mmplayer_t *player = (mmplayer_t *)hplayer;
8383 MMMessageParamType msg_param = {0, };
8386 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8388 LOGW("state changed storage %d:%d", id, state);
8390 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8391 return MM_ERROR_NONE;
8393 /* FIXME: text path should be handled seperately. */
8394 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8395 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8396 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8397 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8398 LOGW("external storage is removed");
8400 if (player->msg_posted == FALSE) {
8401 memset(&msg_param, 0, sizeof(MMMessageParamType));
8402 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8403 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8404 player->msg_posted = TRUE;
8407 /* unrealize the player */
8408 ret = _mmplayer_unrealize(hplayer);
8409 if (ret != MM_ERROR_NONE)
8410 LOGE("failed to unrealize");
8418 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8420 int ret = MM_ERROR_NONE;
8421 mmplayer_t *player = (mmplayer_t *)hplayer;
8422 int idx = 0, total = 0;
8423 gchar *result = NULL, *tmp = NULL;
8426 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8427 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8429 total = *num = g_list_length(player->adaptive_info.var_list);
8431 LOGW("There is no stream variant info.");
8435 result = g_strdup("");
8436 for (idx = 0 ; idx < total ; idx++) {
8437 stream_variant_t *v_data = NULL;
8438 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8441 gchar data[64] = {0};
8442 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8444 tmp = g_strconcat(result, data, NULL);
8448 LOGW("There is no variant data in %d", idx);
8453 *var_info = (char *)result;
8455 LOGD("variant info %d:%s", *num, *var_info);
8461 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8463 int ret = MM_ERROR_NONE;
8464 mmplayer_t *player = (mmplayer_t *)hplayer;
8467 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8469 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8471 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8472 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8473 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8475 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8476 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8477 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8478 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8480 /* FIXME: seek to current position for applying new variant limitation */
8489 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8491 int ret = MM_ERROR_NONE;
8492 mmplayer_t *player = (mmplayer_t *)hplayer;
8495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8496 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8498 *bandwidth = player->adaptive_info.limit.bandwidth;
8499 *width = player->adaptive_info.limit.width;
8500 *height = player->adaptive_info.limit.height;
8502 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8509 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8511 int ret = MM_ERROR_NONE;
8512 mmplayer_t *player = (mmplayer_t *)hplayer;
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8516 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8517 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8519 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8521 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8522 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8523 else /* live case */
8524 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8526 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8533 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8535 #define IDX_FIRST_SW_CODEC 0
8536 mmplayer_t *player = (mmplayer_t *)hplayer;
8537 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8538 MMHandleType attrs = 0;
8541 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8543 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8544 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8545 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8547 switch (stream_type) {
8548 case MM_PLAYER_STREAM_TYPE_AUDIO:
8549 /* to support audio codec selection, codec info have to be added in ini file as below.
8550 audio codec element hw = xxxx
8551 audio codec element sw = avdec */
8552 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8553 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8554 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8555 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8556 LOGE("There is no audio codec info for codec_type %d", codec_type);
8557 return MM_ERROR_PLAYER_NO_OP;
8560 case MM_PLAYER_STREAM_TYPE_VIDEO:
8561 /* to support video codec selection, codec info have to be added in ini file as below.
8562 video codec element hw = omx
8563 video codec element sw = avdec */
8564 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8565 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8566 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8567 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8568 LOGE("There is no video codec info for codec_type %d", codec_type);
8569 return MM_ERROR_PLAYER_NO_OP;
8573 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8574 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8578 LOGD("update %s codec_type to %d", attr_name, codec_type);
8580 attrs = MMPLAYER_GET_ATTRS(player);
8581 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8583 if (mm_attrs_commit_all(player->attrs)) {
8584 LOGE("failed to commit codec_type attributes");
8585 return MM_ERROR_PLAYER_INTERNAL;
8589 return MM_ERROR_NONE;
8593 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8595 mmplayer_t *player = (mmplayer_t *)hplayer;
8596 GstElement *rg_vol_element = NULL;
8600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8602 player->sound.rg_enable = enabled;
8604 /* just hold rgvolume enable value if pipeline is not ready */
8605 if (!player->pipeline || !player->pipeline->audiobin) {
8606 LOGD("pipeline is not ready. holding rgvolume enable value");
8607 return MM_ERROR_NONE;
8610 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8612 if (!rg_vol_element) {
8613 LOGD("rgvolume element is not created");
8614 return MM_ERROR_PLAYER_INTERNAL;
8618 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8620 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8624 return MM_ERROR_NONE;
8628 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8630 mmplayer_t *player = (mmplayer_t *)hplayer;
8631 GstElement *rg_vol_element = NULL;
8632 gboolean enable = FALSE;
8636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8637 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8639 /* just hold enable_rg value if pipeline is not ready */
8640 if (!player->pipeline || !player->pipeline->audiobin) {
8641 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8642 *enabled = player->sound.rg_enable;
8643 return MM_ERROR_NONE;
8646 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8648 if (!rg_vol_element) {
8649 LOGD("rgvolume element is not created");
8650 return MM_ERROR_PLAYER_INTERNAL;
8653 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8654 *enabled = (bool)enable;
8658 return MM_ERROR_NONE;
8662 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8664 mmplayer_t *player = (mmplayer_t *)hplayer;
8665 MMHandleType attrs = 0;
8666 void *handle = NULL;
8667 int ret = MM_ERROR_NONE;
8671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8673 attrs = MMPLAYER_GET_ATTRS(player);
8674 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8676 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8678 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8679 return MM_ERROR_PLAYER_INTERNAL;
8682 player->video_roi.scale_x = scale_x;
8683 player->video_roi.scale_y = scale_y;
8684 player->video_roi.scale_width = scale_width;
8685 player->video_roi.scale_height = scale_height;
8687 /* check video sinkbin is created */
8688 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8689 return MM_ERROR_NONE;
8691 if (!gst_video_overlay_set_video_roi_area(
8692 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8693 scale_x, scale_y, scale_width, scale_height))
8694 ret = MM_ERROR_PLAYER_INTERNAL;
8696 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8697 scale_x, scale_y, scale_width, scale_height);
8705 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8707 mmplayer_t *player = (mmplayer_t *)hplayer;
8708 int ret = MM_ERROR_NONE;
8712 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8713 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8715 *scale_x = player->video_roi.scale_x;
8716 *scale_y = player->video_roi.scale_y;
8717 *scale_width = player->video_roi.scale_width;
8718 *scale_height = player->video_roi.scale_height;
8720 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8721 *scale_x, *scale_y, *scale_width, *scale_height);
8727 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8729 mmplayer_t* player = (mmplayer_t*)hplayer;
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8735 player->client_pid = pid;
8737 LOGD("client pid[%d] %p", pid, player);
8741 return MM_ERROR_NONE;
8745 __mmplayer_update_duration_value(mmplayer_t *player)
8747 gboolean ret = FALSE;
8748 gint64 dur_nsec = 0;
8749 LOGD("try to update duration");
8751 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8752 player->duration = dur_nsec;
8753 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8757 if (player->duration < 0) {
8758 LOGW("duration is Non-Initialized !!!");
8759 player->duration = 0;
8762 /* update streaming service type */
8763 player->streaming_type = _mmplayer_get_stream_service_type(player);
8765 /* check duration is OK */
8766 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8767 /* FIXIT : find another way to get duration here. */
8768 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8774 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8776 /* update audio params
8777 NOTE : We need original audio params and it can be only obtained from src pad of audio
8778 decoder. Below code only valid when we are not using 'resampler' just before
8779 'audioconverter'. */
8780 GstCaps *caps_a = NULL;
8782 gint samplerate = 0, channels = 0;
8783 GstStructure *p = NULL;
8784 GstElement *aconv = NULL;
8786 LOGD("try to update audio attrs");
8788 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8790 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8791 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8792 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8793 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8795 LOGE("there is no audio converter");
8799 pad = gst_element_get_static_pad(aconv, "sink");
8802 LOGW("failed to get pad from audio converter");
8806 caps_a = gst_pad_get_current_caps(pad);
8808 LOGW("not ready to get audio caps");
8809 gst_object_unref(pad);
8813 p = gst_caps_get_structure(caps_a, 0);
8815 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8817 gst_structure_get_int(p, "rate", &samplerate);
8818 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8820 gst_structure_get_int(p, "channels", &channels);
8821 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8823 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8825 gst_caps_unref(caps_a);
8826 gst_object_unref(pad);
8832 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8834 LOGD("try to update video attrs");
8836 GstCaps *caps_v = NULL;
8840 GstStructure *p = NULL;
8842 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8843 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8845 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8847 LOGD("no videosink sink pad");
8851 caps_v = gst_pad_get_current_caps(pad);
8852 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8853 if (!caps_v && player->v_stream_caps) {
8854 caps_v = player->v_stream_caps;
8855 gst_caps_ref(caps_v);
8859 LOGD("no negitiated caps from videosink");
8860 gst_object_unref(pad);
8864 p = gst_caps_get_structure(caps_v, 0);
8865 gst_structure_get_int(p, "width", &width);
8866 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8868 gst_structure_get_int(p, "height", &height);
8869 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8871 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8873 SECURE_LOGD("width : %d height : %d", width, height);
8875 gst_caps_unref(caps_v);
8876 gst_object_unref(pad);
8879 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8880 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8887 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8889 gboolean ret = FALSE;
8890 guint64 data_size = 0;
8894 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8895 if (!player->duration)
8898 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8899 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8900 if (stat(path, &sb) == 0)
8901 data_size = (guint64)sb.st_size;
8903 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8904 data_size = player->http_content_size;
8907 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8910 guint64 bitrate = 0;
8911 guint64 msec_dur = 0;
8913 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8915 bitrate = data_size * 8 * 1000 / msec_dur;
8916 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8917 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8921 LOGD("player duration is less than 0");
8925 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8926 if (player->total_bitrate) {
8927 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8936 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8938 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8939 data->uri_type = uri_type;
8943 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8945 int ret = MM_ERROR_PLAYER_INVALID_URI;
8947 char *buffer = NULL;
8948 char *seperator = strchr(path, ',');
8949 char ext[100] = {0,}, size[100] = {0,};
8952 if ((buffer = strstr(path, "ext="))) {
8953 buffer += strlen("ext=");
8955 if (strlen(buffer)) {
8956 strncpy(ext, buffer, 99);
8958 if ((seperator = strchr(ext, ','))
8959 || (seperator = strchr(ext, ' '))
8960 || (seperator = strchr(ext, '\0'))) {
8961 seperator[0] = '\0';
8966 if ((buffer = strstr(path, "size="))) {
8967 buffer += strlen("size=");
8969 if (strlen(buffer) > 0) {
8970 strncpy(size, buffer, 99);
8972 if ((seperator = strchr(size, ','))
8973 || (seperator = strchr(size, ' '))
8974 || (seperator = strchr(size, '\0'))) {
8975 seperator[0] = '\0';
8978 mem_size = atoi(size);
8983 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8985 if (mem_size && param) {
8986 if (data->input_mem.buf)
8987 free(data->input_mem.buf);
8988 data->input_mem.buf = malloc(mem_size);
8990 if (data->input_mem.buf) {
8991 memcpy(data->input_mem.buf, param, mem_size);
8992 data->input_mem.len = mem_size;
8993 ret = MM_ERROR_NONE;
8995 LOGE("failed to alloc mem %d", mem_size);
8996 ret = MM_ERROR_PLAYER_INTERNAL;
8999 data->input_mem.offset = 0;
9000 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9007 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9009 gchar *location = NULL;
9012 int ret = MM_ERROR_NONE;
9014 if ((path = strstr(uri, "file://"))) {
9015 location = g_filename_from_uri(uri, NULL, &err);
9016 if (!location || (err != NULL)) {
9017 LOGE("Invalid URI '%s' for filesrc: %s", path,
9018 (err != NULL) ? err->message : "unknown error");
9022 MMPLAYER_FREEIF(location);
9024 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9025 return MM_ERROR_PLAYER_INVALID_URI;
9027 LOGD("path from uri: %s", location);
9030 path = (location != NULL) ? (location) : ((char *)uri);
9033 ret = _mmplayer_exist_file_path(path);
9035 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9036 if (ret == MM_ERROR_NONE) {
9037 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9038 if (_mmplayer_is_sdp_file(path)) {
9039 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9040 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9042 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9044 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9045 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9047 LOGE("invalid uri, could not play..");
9048 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9051 MMPLAYER_FREEIF(location);
9056 static mmplayer_video_decoded_data_info_t *
9057 __mmplayer_create_stream_from_pad(GstPad *pad)
9059 GstCaps *caps = NULL;
9060 GstStructure *structure = NULL;
9061 unsigned int fourcc = 0;
9062 const gchar *string_format = NULL;
9063 mmplayer_video_decoded_data_info_t *stream = NULL;
9065 MMPixelFormatType format;
9068 caps = gst_pad_get_current_caps(pad);
9070 LOGE("Caps is NULL.");
9075 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9077 structure = gst_caps_get_structure(caps, 0);
9078 gst_structure_get_int(structure, "width", &width);
9079 gst_structure_get_int(structure, "height", &height);
9080 string_format = gst_structure_get_string(structure, "format");
9083 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9084 format = _mmplayer_get_pixtype(fourcc);
9085 gst_video_info_from_caps(&info, caps);
9086 gst_caps_unref(caps);
9089 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9090 LOGE("Wrong condition!!");
9094 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9096 LOGE("failed to alloc mem for video data");
9100 stream->width = width;
9101 stream->height = height;
9102 stream->format = format;
9103 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9109 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9111 unsigned int pitch = 0;
9112 unsigned int size = 0;
9114 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9117 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9118 bo = gst_tizen_memory_get_bos(mem, index);
9120 stream->bo[index] = tbm_bo_ref(bo);
9122 LOGE("failed to get bo for index %d", index);
9125 for (index = 0; index < stream->plane_num; index++) {
9126 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9127 stream->stride[index] = pitch;
9129 stream->elevation[index] = size / pitch;
9131 stream->elevation[index] = stream->height;
9136 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9138 if (stream->format == MM_PIXEL_FORMAT_I420) {
9139 int ret = TBM_SURFACE_ERROR_NONE;
9140 tbm_surface_h surface;
9141 tbm_surface_info_s info;
9143 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9145 ret = tbm_surface_get_info(surface, &info);
9146 if (ret != TBM_SURFACE_ERROR_NONE) {
9147 tbm_surface_destroy(surface);
9151 tbm_surface_destroy(surface);
9152 stream->stride[0] = info.planes[0].stride;
9153 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9154 stream->stride[1] = info.planes[1].stride;
9155 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9156 stream->stride[2] = info.planes[2].stride;
9157 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9158 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9159 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9160 stream->stride[0] = stream->width * 4;
9161 stream->elevation[0] = stream->height;
9162 stream->bo_size = stream->stride[0] * stream->height;
9164 LOGE("Not support format %d", stream->format);
9172 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9174 tbm_bo_handle thandle;
9176 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9177 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9178 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9182 unsigned char *src = NULL;
9183 unsigned char *dest = NULL;
9184 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9186 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9188 LOGE("fail to gst_memory_map");
9192 if (!mapinfo.data) {
9193 LOGE("data pointer is wrong");
9197 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9198 if (!stream->bo[0]) {
9199 LOGE("Fail to tbm_bo_alloc!!");
9203 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9205 LOGE("thandle pointer is wrong");
9209 if (stream->format == MM_PIXEL_FORMAT_I420) {
9210 src_stride[0] = GST_ROUND_UP_4(stream->width);
9211 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9212 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9213 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9216 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9217 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9219 for (i = 0; i < 3; i++) {
9220 src = mapinfo.data + src_offset[i];
9221 dest = thandle.ptr + dest_offset[i];
9226 for (j = 0; j < stream->height >> k; j++) {
9227 memcpy(dest, src, stream->width>>k);
9228 src += src_stride[i];
9229 dest += stream->stride[i];
9232 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9233 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9235 LOGE("Not support format %d", stream->format);
9239 tbm_bo_unmap(stream->bo[0]);
9240 gst_memory_unmap(mem, &mapinfo);
9246 tbm_bo_unmap(stream->bo[0]);
9249 gst_memory_unmap(mem, &mapinfo);
9255 __mmplayer_set_pause_state(mmplayer_t *player)
9257 if (player->sent_bos)
9260 /* rtsp case, get content attrs by GstMessage */
9261 if (MMPLAYER_IS_RTSP_STREAMING(player))
9264 /* it's first time to update all content attrs. */
9265 _mmplayer_update_content_attrs(player, ATTR_ALL);
9269 __mmplayer_set_playing_state(mmplayer_t *player)
9271 gchar *audio_codec = NULL;
9273 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9274 /* initialize because auto resume is done well. */
9275 player->resumed_by_rewind = FALSE;
9276 player->playback_rate = 1.0;
9279 if (player->sent_bos)
9282 /* try to get content metadata */
9284 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9285 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9286 * legacy mmfw-player api
9288 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9290 if ((player->cmd == MMPLAYER_COMMAND_START)
9291 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9292 __mmplayer_handle_missed_plugin(player);
9295 /* check audio codec field is set or not
9296 * we can get it from typefinder or codec's caps.
9298 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9300 /* The codec format can't be sent for audio only case like amr, mid etc.
9301 * Because, parser don't make related TAG.
9302 * So, if it's not set yet, fill it with found data.
9305 if (g_strrstr(player->type, "audio/midi"))
9306 audio_codec = "MIDI";
9307 else if (g_strrstr(player->type, "audio/x-amr"))
9308 audio_codec = "AMR";
9309 else if (g_strrstr(player->type, "audio/mpeg")
9310 && !g_strrstr(player->type, "mpegversion=(int)1"))
9311 audio_codec = "AAC";
9313 audio_codec = "unknown";
9315 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9317 if (mm_attrs_commit_all(player->attrs))
9318 LOGE("failed to update attributes");
9320 LOGD("set audio codec type with caps");