4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
144 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
177 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
178 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
179 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
180 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
181 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
182 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
183 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
188 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
189 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
192 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
193 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
194 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196 static void __mmplayer_set_pause_state(mmplayer_t *player);
197 static void __mmplayer_set_playing_state(mmplayer_t *player);
198 /*===========================================================================================
200 | FUNCTION DEFINITIONS |
202 ========================================================================================== */
204 /* This function should be called after the pipeline goes PAUSED or higher
207 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
209 static gboolean has_duration = FALSE;
210 static gboolean has_video_attrs = FALSE;
211 static gboolean has_audio_attrs = FALSE;
212 static gboolean has_bitrate = FALSE;
213 gboolean missing_only = FALSE;
214 gboolean all = FALSE;
215 MMHandleType attrs = 0;
219 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
221 /* check player state here */
222 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
223 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
224 /* give warning now only */
225 LOGW("be careful. content attributes may not available in this state ");
228 /* get content attribute first */
229 attrs = MMPLAYER_GET_ATTRS(player);
231 LOGE("cannot get content attribute");
235 /* get update flag */
237 if (flag & ATTR_MISSING_ONLY) {
239 LOGD("updating missed attr only");
242 if (flag & ATTR_ALL) {
244 has_duration = FALSE;
245 has_video_attrs = FALSE;
246 has_audio_attrs = FALSE;
249 LOGD("updating all attrs");
252 if (missing_only && all) {
253 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
254 missing_only = FALSE;
257 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
258 has_duration = __mmplayer_update_duration_value(player);
260 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
261 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
263 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
264 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
266 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
267 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
275 _mmplayer_get_stream_service_type(mmplayer_t *player)
277 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
281 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
283 player->pipeline->mainbin &&
284 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
285 STREAMING_SERVICE_NONE);
287 /* streaming service type if streaming */
288 if (!MMPLAYER_IS_STREAMING(player))
289 return STREAMING_SERVICE_NONE;
291 streaming_type = (player->duration == 0) ?
292 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
294 switch (streaming_type) {
295 case STREAMING_SERVICE_LIVE:
296 LOGD("it's live streaming");
298 case STREAMING_SERVICE_VOD:
299 LOGD("it's vod streaming");
302 LOGE("should not get here");
308 return streaming_type;
311 /* this function sets the player state and also report
312 * it to applicaton by calling callback function
315 _mmplayer_set_state(mmplayer_t *player, int state)
317 MMMessageParamType msg = {0, };
319 MMPLAYER_RETURN_IF_FAIL(player);
321 if (MMPLAYER_CURRENT_STATE(player) == state) {
322 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
323 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
327 /* update player states */
328 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
329 MMPLAYER_CURRENT_STATE(player) = state;
331 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
332 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 MMPLAYER_PRINT_STATE(player);
337 switch (MMPLAYER_CURRENT_STATE(player)) {
338 case MM_PLAYER_STATE_NULL:
339 case MM_PLAYER_STATE_READY:
341 case MM_PLAYER_STATE_PAUSED:
342 __mmplayer_set_pause_state(player);
344 case MM_PLAYER_STATE_PLAYING:
345 __mmplayer_set_playing_state(player);
347 case MM_PLAYER_STATE_NONE:
349 LOGW("invalid target state, there is nothing to do.");
354 /* post message to application */
355 if (MMPLAYER_TARGET_STATE(player) == state) {
356 /* fill the message with state of player */
357 msg.union_type = MM_MSG_UNION_STATE;
358 msg.state.previous = MMPLAYER_PREV_STATE(player);
359 msg.state.current = MMPLAYER_CURRENT_STATE(player);
361 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
363 /* state changed by resource callback */
364 if (player->interrupted_by_resource)
365 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
366 else /* state changed by usecase */
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
370 LOGD("intermediate state, do nothing.");
371 MMPLAYER_PRINT_STATE(player);
375 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
376 && !player->sent_bos) {
377 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
378 player->sent_bos = TRUE;
385 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
387 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
388 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
390 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
392 LOGD("incomming command : %d ", command);
394 current_state = MMPLAYER_CURRENT_STATE(player);
395 pending_state = MMPLAYER_PENDING_STATE(player);
397 MMPLAYER_PRINT_STATE(player);
400 case MMPLAYER_COMMAND_CREATE:
402 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
404 if (current_state == MM_PLAYER_STATE_NULL ||
405 current_state == MM_PLAYER_STATE_READY ||
406 current_state == MM_PLAYER_STATE_PAUSED ||
407 current_state == MM_PLAYER_STATE_PLAYING)
412 case MMPLAYER_COMMAND_DESTROY:
414 /* destroy can called anytime */
416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
420 case MMPLAYER_COMMAND_REALIZE:
422 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
424 if (pending_state != MM_PLAYER_STATE_NONE) {
427 /* need ready state to realize */
428 if (current_state == MM_PLAYER_STATE_READY)
431 if (current_state != MM_PLAYER_STATE_NULL)
437 case MMPLAYER_COMMAND_UNREALIZE:
439 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
441 if (current_state == MM_PLAYER_STATE_NULL)
446 case MMPLAYER_COMMAND_START:
448 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
450 if (pending_state == MM_PLAYER_STATE_NONE) {
451 if (current_state == MM_PLAYER_STATE_PLAYING)
453 else if (current_state != MM_PLAYER_STATE_READY &&
454 current_state != MM_PLAYER_STATE_PAUSED)
456 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
458 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
459 LOGD("player is going to paused state, just change the pending state as playing");
466 case MMPLAYER_COMMAND_STOP:
468 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
470 if (current_state == MM_PLAYER_STATE_READY)
473 /* need playing/paused state to stop */
474 if (current_state != MM_PLAYER_STATE_PLAYING &&
475 current_state != MM_PLAYER_STATE_PAUSED)
480 case MMPLAYER_COMMAND_PAUSE:
482 if (MMPLAYER_IS_LIVE_STREAMING(player))
485 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
486 goto NOT_COMPLETED_SEEK;
488 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
490 if (pending_state == MM_PLAYER_STATE_NONE) {
491 if (current_state == MM_PLAYER_STATE_PAUSED)
493 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
495 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
497 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
498 if (current_state == MM_PLAYER_STATE_PAUSED)
499 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
506 case MMPLAYER_COMMAND_RESUME:
508 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
509 goto NOT_COMPLETED_SEEK;
511 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
513 if (pending_state == MM_PLAYER_STATE_NONE) {
514 if (current_state == MM_PLAYER_STATE_PLAYING)
516 else if (current_state != MM_PLAYER_STATE_PAUSED)
518 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
520 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
521 LOGD("player is going to paused state, just change the pending state as playing");
531 player->cmd = command;
533 return MM_ERROR_NONE;
536 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
537 MMPLAYER_STATE_GET_NAME(current_state), command);
538 return MM_ERROR_PLAYER_INVALID_STATE;
541 LOGW("not completed seek");
542 return MM_ERROR_PLAYER_DOING_SEEK;
545 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
546 return MM_ERROR_PLAYER_NO_OP;
549 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
550 return MM_ERROR_PLAYER_NO_OP;
553 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
555 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
556 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
559 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
560 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
562 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
563 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
565 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
566 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
569 LOGE("invalid mmplayer resource type %d", type);
570 return MM_ERROR_PLAYER_INTERNAL;
573 if (player->hw_resource[type] != NULL) {
574 LOGD("[%d type] resource was already acquired", type);
575 return MM_ERROR_NONE;
578 LOGD("mark for acquire [%d type] resource", type);
579 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
580 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
581 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
582 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
583 return MM_ERROR_PLAYER_INTERNAL;
586 rm_ret = mm_resource_manager_commit(player->resource_manager);
587 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
588 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
589 return MM_ERROR_PLAYER_INTERNAL;
593 return MM_ERROR_NONE;
596 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
598 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 if (player->hw_resource[type] == NULL) {
603 LOGD("there is no acquired [%d type] resource", type);
604 return MM_ERROR_NONE;
607 LOGD("mark for release [%d type] resource", type);
608 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
609 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
610 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
611 return MM_ERROR_PLAYER_INTERNAL;
614 player->hw_resource[type] = NULL;
616 rm_ret = mm_resource_manager_commit(player->resource_manager);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
623 return MM_ERROR_NONE;
627 __mmplayer_initialize_gapless_play(mmplayer_t *player)
633 player->smooth_streaming = FALSE;
634 player->videodec_linked = 0;
635 player->audiodec_linked = 0;
636 player->textsink_linked = 0;
637 player->is_external_subtitle_present = FALSE;
638 player->is_external_subtitle_added_now = FALSE;
639 player->not_supported_codec = MISSING_PLUGIN_NONE;
640 player->can_support_codec = FOUND_PLUGIN_NONE;
641 player->pending_seek.is_pending = false;
642 player->pending_seek.pos = 0;
643 player->msg_posted = FALSE;
644 player->has_many_types = FALSE;
645 player->no_more_pad = FALSE;
646 player->not_found_demuxer = 0;
647 player->seek_state = MMPLAYER_SEEK_NONE;
648 player->is_subtitle_force_drop = FALSE;
649 player->play_subtitle = FALSE;
650 player->adjust_subtitle_pos = 0;
652 player->total_bitrate = 0;
653 player->total_maximum_bitrate = 0;
655 _mmplayer_track_initialize(player);
656 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
658 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
659 player->bitrate[i] = 0;
660 player->maximum_bitrate[i] = 0;
663 if (player->v_stream_caps) {
664 gst_caps_unref(player->v_stream_caps);
665 player->v_stream_caps = NULL;
668 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
670 /* clean found audio decoders */
671 if (player->audio_decoders) {
672 GList *a_dec = player->audio_decoders;
673 for (; a_dec; a_dec = g_list_next(a_dec)) {
674 gchar *name = a_dec->data;
675 MMPLAYER_FREEIF(name);
677 g_list_free(player->audio_decoders);
678 player->audio_decoders = NULL;
681 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
686 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
688 LOGI("set pipeline reconfigure state %d", state);
689 MMPLAYER_RECONFIGURE_LOCK(player);
690 player->gapless.reconfigure = state;
691 if (!state) /* wake up the waiting job */
692 MMPLAYER_RECONFIGURE_SIGNAL(player);
693 MMPLAYER_RECONFIGURE_UNLOCK(player);
697 __mmplayer_gapless_play_thread(gpointer data)
699 mmplayer_t *player = (mmplayer_t *)data;
700 mmplayer_gst_element_t *mainbin = NULL;
702 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
704 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
705 while (!player->gapless_play_thread_exit) {
706 LOGD("gapless play thread started. waiting for signal.");
707 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
709 LOGD("reconfigure pipeline for gapless play.");
711 if (player->gapless_play_thread_exit) {
712 _mmplayer_set_reconfigure_state(player, FALSE);
713 LOGD("exiting gapless play thread");
717 mainbin = player->pipeline->mainbin;
719 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
725 /* Initialize Player values */
726 __mmplayer_initialize_gapless_play(player);
728 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
730 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
736 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
738 GSource *source = NULL;
742 source = g_main_context_find_source_by_id(context, source_id);
743 if (source != NULL) {
744 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
745 g_source_destroy(source);
752 _mmplayer_watcher_removed_notify(gpointer data)
754 mmplayer_t *player = (mmplayer_t *)data;
755 MMPLAYER_RETURN_IF_FAIL(player);
757 MMPLAYER_BUS_WATCHER_LOCK(player);
758 player->bus_watcher = 0;
759 MMPLAYER_BUS_WATCHER_SIGNAL(player);
760 MMPLAYER_BUS_WATCHER_UNLOCK(player);
764 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
766 mmplayer_t *player = (mmplayer_t *)hplayer;
769 MMPLAYER_RETURN_IF_FAIL(player);
771 /* disconnecting bus watch */
772 if (player->bus_watcher > 0) {
773 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
774 MMPLAYER_BUS_WATCHER_LOCK(player);
775 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
776 while (player->bus_watcher > 0)
777 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
778 MMPLAYER_BUS_WATCHER_UNLOCK(player);
780 g_mutex_clear(&player->bus_watcher_mutex);
781 g_cond_clear(&player->bus_watcher_cond);
788 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
790 mmplayer_t *player = (mmplayer_t *)hplayer;
791 GstMessage *msg = NULL;
792 GQueue *queue = NULL;
795 MMPLAYER_RETURN_IF_FAIL(player);
797 /* destroy the gst bus msg thread */
798 if (player->bus_msg_thread) {
799 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
800 player->bus_msg_thread_exit = TRUE;
801 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
802 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
804 LOGD("gst bus msg thread exit.");
805 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
806 player->bus_msg_thread = NULL;
808 g_mutex_clear(&player->bus_msg_thread_mutex);
809 g_cond_clear(&player->bus_msg_thread_cond);
812 g_mutex_lock(&player->bus_msg_q_lock);
813 queue = player->bus_msg_q;
814 while (!g_queue_is_empty(queue)) {
815 msg = (GstMessage *)g_queue_pop_head(queue);
820 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
821 gst_message_unref(msg);
823 g_mutex_unlock(&player->bus_msg_q_lock);
829 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
831 GstElement *parent = NULL;
833 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
834 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
837 MMPLAYER_FSINK_LOCK(player);
839 /* get parent of fakesink */
840 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
842 LOGD("fakesink already removed");
846 gst_element_set_locked_state(fakesink->gst, TRUE);
848 /* setting the state to NULL never returns async
849 * so no need to wait for completion of state transiton
851 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
852 LOGE("fakesink state change failure!");
853 /* FIXIT : should I return here? or try to proceed to next? */
856 /* remove fakesink from it's parent */
857 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
858 LOGE("failed to remove fakesink");
860 gst_object_unref(parent);
865 gst_object_unref(parent);
867 LOGD("state-holder removed");
869 gst_element_set_locked_state(fakesink->gst, FALSE);
871 MMPLAYER_FSINK_UNLOCK(player);
876 gst_element_set_locked_state(fakesink->gst, FALSE);
878 MMPLAYER_FSINK_UNLOCK(player);
882 static GstPadProbeReturn
883 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
885 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
886 return GST_PAD_PROBE_OK;
890 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
892 gint64 stop_running_time = 0;
893 gint64 position_running_time = 0;
897 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
898 if ((player->gapless.update_segment[idx] == TRUE) ||
899 !(player->track[idx].event_probe_id)) {
901 LOGW("[%d] skip", idx);
906 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
908 gst_segment_to_running_time(&player->gapless.segment[idx],
909 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
910 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
912 gst_segment_to_running_time(&player->gapless.segment[idx],
913 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
915 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
917 gst_segment_to_running_time(&player->gapless.segment[idx],
918 GST_FORMAT_TIME, player->duration);
921 position_running_time =
922 gst_segment_to_running_time(&player->gapless.segment[idx],
923 GST_FORMAT_TIME, player->gapless.segment[idx].position);
925 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
926 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
928 GST_TIME_ARGS(stop_running_time),
929 GST_TIME_ARGS(position_running_time),
930 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
931 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
933 position_running_time = MAX(position_running_time, stop_running_time);
934 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
935 GST_FORMAT_TIME, player->gapless.segment[idx].start);
936 position_running_time = MAX(0, position_running_time);
937 position = MAX(position, position_running_time);
941 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
942 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
943 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
945 player->gapless.start_time[stream_type] += position;
951 static GstPadProbeReturn
952 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
954 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
955 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
956 mmplayer_t *player = (mmplayer_t *)data;
957 GstCaps *caps = NULL;
958 GstStructure *str = NULL;
959 const gchar *name = NULL;
960 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
961 gboolean caps_ret = TRUE;
963 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
964 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
965 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
966 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
967 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
970 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
974 if (strstr(name, "audio")) {
975 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
976 } else if (strstr(name, "video")) {
977 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
979 /* text track is not supportable */
980 LOGE("invalid name %s", name);
984 switch (GST_EVENT_TYPE(event)) {
987 /* in case of gapless, drop eos event not to send it to sink */
988 if (player->gapless.reconfigure && !player->msg_posted) {
989 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
990 ret = GST_PAD_PROBE_DROP;
994 case GST_EVENT_STREAM_START:
996 __mmplayer_gst_selector_update_start_time(player, stream_type);
999 case GST_EVENT_FLUSH_STOP:
1001 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1002 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1003 player->gapless.start_time[stream_type] = 0;
1006 case GST_EVENT_SEGMENT:
1011 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1012 gst_event_copy_segment(event, &segment);
1014 if (segment.format != GST_FORMAT_TIME)
1017 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1018 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1019 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1020 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1021 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1022 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1024 /* keep the all the segment ev to cover the seeking */
1025 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1026 player->gapless.update_segment[stream_type] = TRUE;
1028 if (!player->gapless.running)
1031 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1033 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1035 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1036 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1037 gst_event_unref(event);
1038 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1044 gdouble proportion = 0.0;
1045 GstClockTimeDiff diff = 0;
1046 GstClockTime timestamp = 0;
1047 gint64 running_time_diff = -1;
1048 GstQOSType type = 0;
1049 GstEvent *tmpev = NULL;
1051 running_time_diff = player->gapless.segment[stream_type].base;
1053 if (running_time_diff <= 0) /* don't need to adjust */
1056 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1057 gst_event_unref(event);
1059 if (timestamp < running_time_diff) {
1060 LOGW("QOS event from previous group");
1061 ret = GST_PAD_PROBE_DROP;
1066 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1067 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1068 stream_type, GST_TIME_ARGS(timestamp),
1069 GST_TIME_ARGS(running_time_diff),
1070 GST_TIME_ARGS(timestamp - running_time_diff));
1073 timestamp -= running_time_diff;
1075 /* That case is invalid for QoS events */
1076 if (diff < 0 && -diff > timestamp) {
1077 LOGW("QOS event from previous group");
1078 ret = GST_PAD_PROBE_DROP;
1082 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1083 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1093 gst_caps_unref(caps);
1097 /* create fakesink for audio or video path witout audiobin or videobin */
1099 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1101 GstElement *pipeline = NULL;
1102 GstElement *fakesink = NULL;
1103 GstPad *sinkpad = NULL;
1106 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1108 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1111 fakesink = gst_element_factory_make("fakesink", NULL);
1112 if (fakesink == NULL) {
1113 LOGE("failed to create fakesink");
1117 /* store it as it's sink element */
1118 __mmplayer_add_sink(player, fakesink);
1120 gst_bin_add(GST_BIN(pipeline), fakesink);
1123 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1125 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1127 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1128 LOGE("failed to link fakesink");
1129 gst_object_unref(GST_OBJECT(fakesink));
1133 if (strstr(name, "video")) {
1134 if (player->v_stream_caps) {
1135 gst_caps_unref(player->v_stream_caps);
1136 player->v_stream_caps = NULL;
1138 if (player->ini.set_dump_element_flag)
1139 __mmplayer_add_dump_buffer_probe(player, fakesink);
1142 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1143 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1147 gst_object_unref(GST_OBJECT(sinkpad));
1154 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1156 GstElement *pipeline = NULL;
1157 GstElement *selector = NULL;
1158 GstPad *srcpad = NULL;
1161 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1163 selector = gst_element_factory_make("input-selector", NULL);
1165 LOGE("failed to create input-selector");
1168 g_object_set(selector, "sync-streams", TRUE, NULL);
1170 player->pipeline->mainbin[elem_idx].id = elem_idx;
1171 player->pipeline->mainbin[elem_idx].gst = selector;
1173 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1175 srcpad = gst_element_get_static_pad(selector, "src");
1177 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1178 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1179 __mmplayer_gst_selector_blocked, NULL, NULL);
1180 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1181 __mmplayer_gst_selector_event_probe, player, NULL);
1183 gst_element_set_state(selector, GST_STATE_PAUSED);
1185 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1186 gst_bin_add(GST_BIN(pipeline), selector);
1188 gst_object_unref(GST_OBJECT(srcpad));
1195 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1197 mmplayer_t *player = (mmplayer_t *)data;
1198 GstElement *selector = NULL;
1199 GstCaps *caps = NULL;
1200 GstStructure *str = NULL;
1201 const gchar *name = NULL;
1202 GstPad *sinkpad = NULL;
1203 gboolean first_track = FALSE;
1204 gboolean caps_ret = TRUE;
1206 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1207 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1210 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1211 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1213 LOGD("pad-added signal handling");
1215 /* get mimetype from caps */
1216 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1220 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1222 LOGD("detected mimetype : %s", name);
1225 if (strstr(name, "video")) {
1227 gchar *caps_str = NULL;
1229 caps_str = gst_caps_to_string(caps);
1230 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1231 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1232 player->set_mode.video_zc = true;
1234 MMPLAYER_FREEIF(caps_str);
1236 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1237 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1239 LOGD("surface type : %d", stype);
1241 if (MMPLAYER_IS_MS_BUFF_SRC(player) || !MMPLAYER_USE_DECODEBIN(player)) {
1242 __mmplayer_gst_create_sinkbin(elem, pad, player);
1246 /* in case of exporting video frame, it requires the 360 video filter.
1247 * it will be handled in _no_more_pads(). */
1248 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1249 __mmplayer_gst_make_fakesink(player, pad, name);
1253 LOGD("video selector is required");
1254 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1255 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1256 } else if (strstr(name, "audio")) {
1257 gint samplerate = 0;
1260 if (MMPLAYER_IS_MS_BUFF_SRC(player) || !MMPLAYER_USE_DECODEBIN(player) || player->build_audio_offload) {
1261 if (player->build_audio_offload)
1262 player->no_more_pad = TRUE; /* remove state holder */
1263 __mmplayer_gst_create_sinkbin(elem, pad, player);
1267 gst_structure_get_int(str, "rate", &samplerate);
1268 gst_structure_get_int(str, "channels", &channels);
1270 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1271 __mmplayer_gst_make_fakesink(player, pad, name);
1275 LOGD("audio selector is required");
1276 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1277 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1279 } else if (strstr(name, "text")) {
1280 LOGD("text selector is required");
1281 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1282 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1284 LOGE("invalid caps info");
1288 /* check selector and create it */
1289 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1290 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1295 LOGD("input-selector is already created.");
1299 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1301 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1303 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1304 LOGE("failed to link selector");
1305 gst_object_unref(GST_OBJECT(selector));
1310 LOGD("this track will be activated");
1311 g_object_set(selector, "active-pad", sinkpad, NULL);
1314 if (MMPLAYER_USE_DECODEBIN(player))
1315 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1321 gst_caps_unref(caps);
1324 gst_object_unref(GST_OBJECT(sinkpad));
1332 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1334 GstPad *srcpad = NULL;
1337 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1339 LOGD("type %d", type);
1342 LOGD("there is no %d track", type);
1346 srcpad = gst_element_get_static_pad(selector, "src");
1348 LOGE("failed to get srcpad from selector");
1352 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1354 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1356 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1357 if (player->track[type].block_id) {
1358 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1359 player->track[type].block_id = 0;
1363 gst_object_unref(GST_OBJECT(srcpad));
1372 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1374 gint active_index = 0;
1377 MMPLAYER_RETURN_IF_FAIL(player);
1379 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1381 /* change track to active pad */
1382 active_index = player->track[type].active_track_index;
1383 if ((active_index != DEFAULT_TRACK) &&
1384 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1385 LOGW("failed to change %d type track to %d", type, active_index);
1386 player->track[type].active_track_index = DEFAULT_TRACK;
1390 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1391 mm_player_set_attribute((MMHandleType)player, NULL,
1392 "content_text_track_num", player->track[type].total_track_num,
1393 "current_text_track_index", player->track[type].active_track_index, NULL);
1400 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1403 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1405 if (!audio_selector) {
1406 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1408 /* in case the source is changed, output can be changed. */
1409 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1410 LOGD("remove previous audiobin if it exist");
1412 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1413 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1415 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1416 MMPLAYER_FREEIF(player->pipeline->audiobin);
1419 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1420 _mmplayer_pipeline_complete(NULL, player);
1425 /* apply the audio track information */
1426 if (MMPLAYER_USE_DECODEBIN(player))
1427 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1429 /* create audio sink path */
1430 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1431 LOGE("failed to create audio sink path");
1440 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1443 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1445 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1446 LOGD("text path is not supproted");
1450 /* apply the text track information */
1451 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1453 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1454 player->has_closed_caption = TRUE;
1456 /* create text decode path */
1457 player->no_more_pad = TRUE;
1459 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1460 LOGE("failed to create text sink path");
1469 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1471 gint64 dur_bytes = 0L;
1474 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1475 player->pipeline->mainbin && player->streamer, FALSE);
1477 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1478 LOGE("fail to get duration.");
1480 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1481 * use file information was already set on Q2 when it was created. */
1482 _mm_player_streaming_set_queue2(player->streamer,
1483 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1484 TRUE, /* use_buffering */
1485 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1486 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1493 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1495 mmplayer_t *player = NULL;
1496 GstElement *video_selector = NULL;
1497 GstElement *audio_selector = NULL;
1498 GstElement *text_selector = NULL;
1501 player = (mmplayer_t *)data;
1503 LOGD("no-more-pad signal handling");
1505 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1506 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1507 LOGW("player is shutting down");
1511 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1512 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1513 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1514 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1515 LOGE("failed to set queue2 buffering");
1520 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1521 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1522 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1524 if (!video_selector && !audio_selector && !text_selector) {
1525 LOGW("there is no selector");
1526 player->no_more_pad = TRUE;
1530 /* create video path followed by video-select */
1531 if (video_selector && !audio_selector && !text_selector)
1532 player->no_more_pad = TRUE;
1534 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1537 /* create audio path followed by audio-select */
1538 if (audio_selector && !text_selector)
1539 player->no_more_pad = TRUE;
1541 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1544 /* create text path followed by text-select */
1545 __mmplayer_create_text_sink_path(player, text_selector);
1548 _mmplayer_set_reconfigure_state(player, FALSE);
1553 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1555 gboolean ret = FALSE;
1556 GstElement *pipeline = NULL;
1557 GstPad *sinkpad = NULL;
1560 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1561 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1563 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1565 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1567 LOGE("failed to get pad from sinkbin");
1573 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1574 LOGE("failed to link sinkbin for reusing");
1575 goto EXIT; /* exit either pass or fail */
1579 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1580 LOGE("failed to set state(READY) to sinkbin");
1585 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1586 LOGE("failed to add sinkbin to pipeline");
1591 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1592 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1597 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1598 LOGE("failed to set state(PAUSED) to sinkbin");
1607 gst_object_unref(GST_OBJECT(sinkpad));
1615 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1617 mmplayer_t *player = NULL;
1618 GstCaps *caps = NULL;
1619 gchar *caps_str = NULL;
1620 GstStructure *str = NULL;
1621 const gchar *name = NULL;
1622 GstElement *sinkbin = NULL;
1623 gboolean reusing = FALSE;
1624 gboolean caps_ret = TRUE;
1625 gchar *sink_pad_name = "sink";
1628 player = (mmplayer_t *)data;
1631 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1632 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1634 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1638 caps_str = gst_caps_to_string(caps);
1640 LOGD("detected mimetype : %s", name);
1642 if (strstr(name, "audio")) {
1643 if (player->pipeline->audiobin == NULL) {
1644 const gchar *audio_format = gst_structure_get_string(str, "format");
1646 LOGD("original audio format %s", audio_format);
1647 mm_player_set_attribute((MMHandleType)player, NULL,
1648 "content_audio_format", audio_format, strlen(audio_format), NULL);
1651 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1652 LOGE("failed to create audiobin. continuing without audio");
1656 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1657 LOGD("creating audiobin success");
1660 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1661 LOGD("reusing audiobin");
1662 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1664 } else if (strstr(name, "video")) {
1665 /* 1. zero copy is updated at _decode_pad_added()
1666 * 2. NULL surface type is handled in _decode_pad_added() */
1667 LOGD("zero copy %d", player->set_mode.video_zc);
1668 if (player->pipeline->videobin == NULL) {
1669 int surface_type = 0;
1670 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1671 LOGD("display_surface_type (%d)", surface_type);
1673 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1674 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1675 LOGE("failed to acquire video overlay resource");
1679 player->interrupted_by_resource = FALSE;
1681 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1682 LOGE("failed to create videobin. continuing without video");
1686 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1687 LOGD("creating videosink bin success");
1690 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1691 LOGD("re-using videobin");
1692 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1694 } else if (strstr(name, "text")) {
1695 if (player->pipeline->textbin == NULL) {
1696 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1697 LOGE("failed to create text sink bin. continuing without text");
1701 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1702 player->textsink_linked = 1;
1703 LOGD("creating textsink bin success");
1705 if (!player->textsink_linked) {
1706 LOGD("re-using textbin");
1708 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1709 player->textsink_linked = 1;
1711 /* linked textbin exist which means that the external subtitle path exist already */
1712 LOGW("ignoring internal subtutle since external subtitle is available");
1715 sink_pad_name = "text_sink";
1717 LOGW("unknown mime type %s, ignoring it", name);
1721 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1724 LOGD("[handle: %p] success to create and link sink bin", player);
1726 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1727 * streaming task. if the task blocked, then buffer will not flow to the next element
1728 *(autoplugging element). so this is special hack for streaming. please try to remove it
1730 /* dec stream count. we can remove fakesink if it's zero */
1731 if (player->num_dynamic_pad)
1732 player->num_dynamic_pad--;
1734 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1736 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1737 _mmplayer_pipeline_complete(NULL, player);
1741 MMPLAYER_FREEIF(caps_str);
1744 gst_caps_unref(caps);
1750 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1752 int required_angle = 0; /* Angle required for straight view */
1753 int rotation_angle = 0;
1755 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1756 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1758 /* Counter clockwise */
1759 switch (orientation) {
1764 required_angle = 270;
1767 required_angle = 180;
1770 required_angle = 90;
1774 rotation_angle = display_angle + required_angle;
1775 if (rotation_angle >= 360)
1776 rotation_angle -= 360;
1778 /* chech if supported or not */
1779 if (rotation_angle % 90) {
1780 LOGD("not supported rotation angle = %d", rotation_angle);
1784 switch (rotation_angle) {
1786 *value = MM_DISPLAY_ROTATION_NONE;
1789 *value = MM_DISPLAY_ROTATION_90;
1792 *value = MM_DISPLAY_ROTATION_180;
1795 *value = MM_DISPLAY_ROTATION_270;
1799 LOGD("setting rotation property value : %d", *value);
1805 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1807 int display_rotation = 0;
1808 gchar *org_orient = NULL;
1809 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1812 LOGE("cannot get content attribute");
1813 return MM_ERROR_PLAYER_INTERNAL;
1816 if (display_angle) {
1817 /* update user roation */
1818 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1820 /* Counter clockwise */
1821 switch (display_rotation) {
1822 case MM_DISPLAY_ROTATION_NONE:
1825 case MM_DISPLAY_ROTATION_90:
1826 *display_angle = 90;
1828 case MM_DISPLAY_ROTATION_180:
1829 *display_angle = 180;
1831 case MM_DISPLAY_ROTATION_270:
1832 *display_angle = 270;
1835 LOGW("wrong angle type : %d", display_rotation);
1838 LOGD("check user angle: %d", *display_angle);
1842 /* Counter clockwise */
1843 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1846 if (!strcmp(org_orient, "rotate-90"))
1848 else if (!strcmp(org_orient, "rotate-180"))
1850 else if (!strcmp(org_orient, "rotate-270"))
1853 LOGD("original rotation is %s", org_orient);
1855 LOGD("content_video_orientation get fail");
1858 LOGD("check orientation: %d", *orientation);
1861 return MM_ERROR_NONE;
1864 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1866 int rotation_value = 0;
1867 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1868 int display_angle = 0;
1871 /* check video sinkbin is created */
1872 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1875 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1877 /* get rotation value to set */
1878 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1879 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1880 LOGD("set video param : rotate %d", rotation_value);
1883 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1885 MMHandleType attrs = 0;
1889 /* check video sinkbin is created */
1890 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1893 attrs = MMPLAYER_GET_ATTRS(player);
1894 MMPLAYER_RETURN_IF_FAIL(attrs);
1896 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1897 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1898 LOGD("set video param : visible %d", visible);
1901 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1903 MMHandleType attrs = 0;
1904 int display_method = 0;
1907 /* check video sinkbin is created */
1908 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1911 attrs = MMPLAYER_GET_ATTRS(player);
1912 MMPLAYER_RETURN_IF_FAIL(attrs);
1914 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1915 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1916 LOGD("set video param : method %d", display_method);
1919 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1921 MMHandleType attrs = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 gst_video_overlay_set_video_roi_area(
1936 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1937 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1938 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1939 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1942 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1944 MMHandleType attrs = 0;
1949 int win_roi_width = 0;
1950 int win_roi_height = 0;
1953 /* check video sinkbin is created */
1954 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1957 attrs = MMPLAYER_GET_ATTRS(player);
1958 MMPLAYER_RETURN_IF_FAIL(attrs);
1960 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1961 MMPLAYER_RETURN_IF_FAIL(handle);
1963 /* It should be set after setting window */
1964 mm_attrs_multiple_get(attrs, NULL,
1965 "display_win_roi_x", &win_roi_x,
1966 "display_win_roi_y", &win_roi_y,
1967 "display_win_roi_width", &win_roi_width,
1968 "display_win_roi_height", &win_roi_height, NULL);
1970 /* After setting window handle, set display roi area */
1971 gst_video_overlay_set_display_roi_area(
1972 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1973 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1974 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1975 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1978 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1980 MMHandleType attrs = 0;
1983 /* check video sinkbin is created */
1984 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1987 attrs = MMPLAYER_GET_ATTRS(player);
1988 MMPLAYER_RETURN_IF_FAIL(attrs);
1990 /* common case if using overlay surface */
1991 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1992 MMPLAYER_RETURN_IF_FAIL(handle);
1994 /* default is using wl_surface_id */
1995 LOGD("set video param : wl_surface_id %d", handle);
1996 gst_video_overlay_set_wl_window_wl_surface_id(
1997 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2002 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2004 gboolean update_all_param = FALSE;
2008 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2009 LOGW("videosink is not ready yet");
2010 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2013 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2014 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2015 return MM_ERROR_PLAYER_INTERNAL;
2018 LOGD("param_name : %s", param_name);
2019 if (!g_strcmp0(param_name, "update_all_param"))
2020 update_all_param = TRUE;
2022 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2023 __mmplayer_video_param_set_display_overlay(player);
2024 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2025 __mmplayer_video_param_set_display_method(player);
2026 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2027 __mmplayer_video_param_set_display_visible(player);
2028 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2029 __mmplayer_video_param_set_display_rotation(player);
2030 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2031 __mmplayer_video_param_set_roi_area(player);
2032 if (update_all_param)
2033 __mmplayer_video_param_set_video_roi_area(player);
2037 return MM_ERROR_NONE;
2041 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2043 gboolean disable_overlay = FALSE;
2044 mmplayer_t *player = (mmplayer_t *)hplayer;
2047 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2048 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2049 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2050 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2052 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2053 LOGW("Display control is not supported");
2054 return MM_ERROR_PLAYER_INTERNAL;
2057 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2059 if (audio_only == (bool)disable_overlay) {
2060 LOGE("It's the same with current setting: (%d)", audio_only);
2061 return MM_ERROR_NONE;
2065 LOGE("disable overlay");
2066 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2068 /* release overlay resource */
2069 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2070 LOGE("failed to release overlay resource");
2074 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2075 LOGE("failed to acquire video overlay resource");
2078 player->interrupted_by_resource = FALSE;
2080 LOGD("enable overlay");
2081 __mmplayer_video_param_set_display_overlay(player);
2082 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2087 return MM_ERROR_NONE;
2091 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2093 mmplayer_t *player = (mmplayer_t *)hplayer;
2094 gboolean disable_overlay = FALSE;
2098 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2099 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2100 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2101 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2102 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2104 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2105 LOGW("Display control is not supported");
2106 return MM_ERROR_PLAYER_INTERNAL;
2109 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2111 *paudio_only = (bool)disable_overlay;
2113 LOGD("audio_only : %d", *paudio_only);
2117 return MM_ERROR_NONE;
2121 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2123 GList *bucket = element_bucket;
2124 mmplayer_gst_element_t *element = NULL;
2125 mmplayer_gst_element_t *prv_element = NULL;
2126 GstElement *tee_element = NULL;
2127 gint successful_link_count = 0;
2131 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2133 prv_element = (mmplayer_gst_element_t *)bucket->data;
2134 bucket = bucket->next;
2136 for (; bucket; bucket = bucket->next) {
2137 element = (mmplayer_gst_element_t *)bucket->data;
2139 if (element && element->gst) {
2140 if (prv_element && prv_element->gst) {
2141 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2143 prv_element->gst = tee_element;
2145 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2146 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2147 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2151 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2152 LOGD("linking [%s] to [%s] success",
2153 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2154 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2155 successful_link_count++;
2156 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2157 LOGD("keep audio-tee element for next audio pipeline branch");
2158 tee_element = prv_element->gst;
2161 LOGD("linking [%s] to [%s] failed",
2162 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2163 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2169 prv_element = element;
2174 return successful_link_count;
2178 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2180 GList *bucket = element_bucket;
2181 mmplayer_gst_element_t *element = NULL;
2182 int successful_add_count = 0;
2186 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2187 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2189 for (; bucket; bucket = bucket->next) {
2190 element = (mmplayer_gst_element_t *)bucket->data;
2192 if (element && element->gst) {
2193 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2194 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2195 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2196 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2199 successful_add_count++;
2205 return successful_add_count;
2209 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2211 mmplayer_t *player = (mmplayer_t *)data;
2212 GstCaps *caps = NULL;
2213 GstStructure *str = NULL;
2215 gboolean caps_ret = TRUE;
2219 MMPLAYER_RETURN_IF_FAIL(pad);
2220 MMPLAYER_RETURN_IF_FAIL(unused);
2221 MMPLAYER_RETURN_IF_FAIL(data);
2223 caps = gst_pad_get_current_caps(pad);
2227 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2231 LOGD("name = %s", name);
2233 if (strstr(name, "audio")) {
2234 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2236 if (player->audio_stream_changed_cb) {
2237 LOGE("call the audio stream changed cb");
2238 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2240 } else if (strstr(name, "video")) {
2241 if ((name = gst_structure_get_string(str, "format")))
2242 player->set_mode.video_zc = name[0] == 'S';
2244 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2245 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2247 LOGW("invalid caps info");
2252 gst_caps_unref(caps);
2260 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2265 MMPLAYER_RETURN_IF_FAIL(player);
2267 if (player->audio_stream_buff_list) {
2268 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2269 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2272 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2273 __mmplayer_audio_stream_send_data(player, tmp);
2275 MMPLAYER_FREEIF(tmp->pcm_data);
2276 MMPLAYER_FREEIF(tmp);
2279 g_list_free(player->audio_stream_buff_list);
2280 player->audio_stream_buff_list = NULL;
2287 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2289 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2292 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2294 audio_stream.bitrate = a_buffer->bitrate;
2295 audio_stream.channel = a_buffer->channel;
2296 audio_stream.channel_mask = a_buffer->channel_mask;
2297 audio_stream.data_size = a_buffer->data_size;
2298 audio_stream.data = a_buffer->pcm_data;
2299 audio_stream.pcm_format = a_buffer->pcm_format;
2301 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2303 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2309 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2311 mmplayer_t *player = (mmplayer_t *)data;
2312 const gchar *pcm_format = NULL;
2315 guint64 channel_mask = 0;
2316 void *a_data = NULL;
2318 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2319 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2323 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2325 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2326 a_data = mapinfo.data;
2327 a_size = mapinfo.size;
2329 GstCaps *caps = gst_pad_get_current_caps(pad);
2330 GstStructure *structure = gst_caps_get_structure(caps, 0);
2332 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2334 pcm_format = gst_structure_get_string(structure, "format");
2335 gst_structure_get_int(structure, "rate", &rate);
2336 gst_structure_get_int(structure, "channels", &channel);
2337 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2338 gst_caps_unref(GST_CAPS(caps));
2340 /* In case of the sync is false, use buffer list. *
2341 * The num of buffer list depends on the num of audio channels */
2342 if (player->audio_stream_buff_list) {
2343 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2344 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2346 if (channel_mask == tmp->channel_mask) {
2348 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2350 if (tmp->data_size + a_size < tmp->buff_size) {
2351 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2352 tmp->data_size += a_size;
2354 /* send data to client */
2355 __mmplayer_audio_stream_send_data(player, tmp);
2357 if (a_size > tmp->buff_size) {
2358 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2359 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2360 if (tmp->pcm_data == NULL) {
2361 LOGE("failed to realloc data.");
2364 tmp->buff_size = a_size;
2366 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2367 memcpy(tmp->pcm_data, a_data, a_size);
2368 tmp->data_size = a_size;
2373 LOGE("data is empty in list.");
2379 /* create new audio stream data for newly found audio channel */
2380 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2381 if (a_buffer == NULL) {
2382 LOGE("failed to alloc data.");
2385 a_buffer->bitrate = rate;
2386 a_buffer->channel = channel;
2387 a_buffer->channel_mask = channel_mask;
2388 a_buffer->data_size = a_size;
2389 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2391 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2392 /* If sync is FALSE, use buffer list to reduce the IPC. */
2393 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2394 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2395 if (a_buffer->pcm_data == NULL) {
2396 LOGE("failed to alloc data.");
2397 MMPLAYER_FREEIF(a_buffer);
2400 memcpy(a_buffer->pcm_data, a_data, a_size);
2402 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2404 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2406 /* If sync is TRUE, send data directly. */
2407 a_buffer->pcm_data = a_data;
2408 __mmplayer_audio_stream_send_data(player, a_buffer);
2409 MMPLAYER_FREEIF(a_buffer);
2413 gst_buffer_unmap(buffer, &mapinfo);
2418 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2420 mmplayer_t *player = (mmplayer_t *)data;
2421 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2422 GstPad *sinkpad = NULL;
2423 GstElement *queue = NULL, *sink = NULL;
2426 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2428 queue = gst_element_factory_make("queue", NULL);
2429 if (queue == NULL) {
2430 LOGD("fail make queue");
2434 sink = gst_element_factory_make("fakesink", NULL);
2436 LOGD("fail make fakesink");
2440 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2442 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2443 LOGW("failed to link queue & sink");
2447 sinkpad = gst_element_get_static_pad(queue, "sink");
2449 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2450 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2454 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2456 gst_object_unref(sinkpad);
2457 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2458 g_object_set(sink, "sync", TRUE, NULL);
2459 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2461 /* keep the first sink reference only */
2462 if (!audiobin[MMPLAYER_A_SINK].gst) {
2463 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2464 audiobin[MMPLAYER_A_SINK].gst = sink;
2468 _mmplayer_add_signal_connection(player,
2470 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2472 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2475 __mmplayer_add_sink(player, sink);
2477 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2478 LOGE("failed to sync state");
2482 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2483 LOGE("failed to sync state");
2491 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2493 gst_object_unref(GST_OBJECT(queue));
2497 gst_object_unref(GST_OBJECT(sink));
2501 gst_object_unref(GST_OBJECT(sinkpad));
2509 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2511 mmplayer_t *player = (mmplayer_t *)data;
2514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2516 player->no_more_pad = TRUE;
2517 _mmplayer_pipeline_complete(NULL, player);
2524 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2526 #define MAX_PROPS_LEN 128
2527 mmplayer_gst_element_t *audiobin = NULL;
2528 gint latency_mode = 0;
2529 gchar *stream_type = NULL;
2530 gchar *latency = NULL;
2532 gchar stream_props[MAX_PROPS_LEN] = {0,};
2533 GstStructure *props = NULL;
2536 * It should be set after player creation through attribute.
2537 * But, it can not be changed during playing.
2540 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2542 audiobin = player->pipeline->audiobin;
2544 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2545 if (player->sound.mute) {
2546 LOGD("mute enabled");
2547 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2550 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2551 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2554 snprintf(stream_props, sizeof(stream_props) - 1,
2555 "props,application.process.id.origin=%d", player->client_pid);
2557 snprintf(stream_props, sizeof(stream_props) - 1,
2558 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2559 stream_type, stream_id, player->client_pid);
2561 props = gst_structure_from_string(stream_props, NULL);
2562 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2563 LOGI("props result[%s].", stream_props);
2564 gst_structure_free(props);
2566 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2568 switch (latency_mode) {
2569 case AUDIO_LATENCY_MODE_LOW:
2570 latency = g_strdup("low");
2572 case AUDIO_LATENCY_MODE_MID:
2573 latency = g_strdup("mid");
2575 case AUDIO_LATENCY_MODE_HIGH:
2576 latency = g_strdup("high");
2579 latency = g_strdup("mid");
2583 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2585 LOGD("audiosink property - latency=%s", latency);
2587 MMPLAYER_FREEIF(latency);
2593 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2595 mmplayer_gst_element_t *audiobin = NULL;
2598 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2599 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2601 audiobin = player->pipeline->audiobin;
2603 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2604 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2605 LOGE("failed to create media stream info");
2606 return MM_ERROR_PLAYER_INTERNAL;
2609 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2611 if (player->video360_yaw_radians <= M_PI &&
2612 player->video360_yaw_radians >= -M_PI &&
2613 player->video360_pitch_radians <= M_PI_2 &&
2614 player->video360_pitch_radians >= -M_PI_2) {
2615 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2616 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2617 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2618 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2619 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2620 "source-orientation-y", player->video360_metadata.init_view_heading,
2621 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2625 return MM_ERROR_NONE;
2629 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2631 mmplayer_gst_element_t *audiobin = NULL;
2632 GstPad *sink_pad = NULL;
2633 GstCaps *acaps = NULL;
2635 int pitch_control = 0;
2636 double pitch_value = 1.0;
2639 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2640 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2642 audiobin = player->pipeline->audiobin;
2644 LOGD("make element for normal audio playback");
2646 /* audio bin structure for playback. {} means optional.
2647 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2649 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2650 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2653 /* for pitch control */
2654 mm_attrs_multiple_get(player->attrs, NULL,
2655 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2656 MM_PLAYER_PITCH_VALUE, &pitch_value,
2659 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2660 if (pitch_control && (player->videodec_linked == 0)) {
2661 GstElementFactory *factory;
2663 factory = gst_element_factory_find("pitch");
2665 gst_object_unref(factory);
2668 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2672 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2674 LOGW("there is no pitch element");
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2681 /* replaygain volume */
2682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2683 if (player->sound.rg_enable)
2684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2686 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2689 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2691 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2692 /* currently, only openalsink uses volume element */
2693 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2694 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2696 if (player->sound.mute) {
2697 LOGD("mute enabled");
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2702 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2704 /* audio effect element. if audio effect is enabled */
2705 if ((strcmp(player->ini.audioeffect_element, ""))
2707 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2710 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2712 if ((!player->bypass_audio_effect)
2713 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2714 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2715 if (!_mmplayer_audio_effect_custom_apply(player))
2716 LOGI("apply audio effect(custom) setting success");
2720 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2721 && (player->set_mode.rich_audio)) {
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2726 /* create audio sink */
2727 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2728 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2729 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2731 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2732 if (player->is_360_feature_enabled &&
2733 player->is_content_spherical &&
2735 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2736 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2737 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2739 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2741 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2744 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2746 gst_caps_unref(acaps);
2748 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2750 player->is_openal_plugin_used = TRUE;
2752 if (player->is_360_feature_enabled && player->is_content_spherical)
2753 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2754 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2757 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2758 (player->videodec_linked && player->ini.use_system_clock)) {
2759 LOGD("system clock will be used.");
2760 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2763 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2764 __mmplayer_gst_set_pulsesink_property(player);
2765 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2766 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2771 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2772 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2774 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2775 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2776 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2777 gst_object_unref(GST_OBJECT(sink_pad));
2779 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2782 return MM_ERROR_NONE;
2784 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2786 return MM_ERROR_PLAYER_INTERNAL;
2790 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2792 mmplayer_gst_element_t *audiobin = NULL;
2793 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2795 gchar *dst_format = NULL;
2797 int dst_samplerate = 0;
2798 int dst_channels = 0;
2799 GstCaps *caps = NULL;
2800 char *caps_str = NULL;
2803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2804 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2806 audiobin = player->pipeline->audiobin;
2808 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2810 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2812 [case 1] extract interleave audio pcm without playback
2813 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2814 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2816 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2818 [case 2] deinterleave for each channel without playback
2819 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2820 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2822 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2823 - fakesink (sync or not)
2826 [case 3] [case 1(sync only)] + playback
2827 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2829 * src - ... - tee - queue1 - playback path
2830 - queue2 - [case1 pipeline with sync]
2832 [case 4] [case 2(sync only)] + playback
2833 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2835 * src - ... - tee - queue1 - playback path
2836 - queue2 - [case2 pipeline with sync]
2840 /* 1. create tee and playback path
2841 'tee' should be added at first to copy the decoded stream
2843 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2844 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2845 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2847 /* tee - path 1 : for playback path */
2848 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2849 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2851 /* tee - path 2 : for extract path */
2852 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2853 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2856 /* if there is tee, 'tee - path 2' is linked here */
2858 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2861 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2863 /* 2. decide the extract pcm format */
2864 mm_attrs_multiple_get(player->attrs, NULL,
2865 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2866 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2867 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2870 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2871 dst_format, dst_len, dst_samplerate, dst_channels);
2873 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2874 mm_attrs_multiple_get(player->attrs, NULL,
2875 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2876 "content_audio_samplerate", &dst_samplerate,
2877 "content_audio_channels", &dst_channels,
2880 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2881 dst_format, dst_len, dst_samplerate, dst_channels);
2883 /* If there is no enough information, set it to platform default value. */
2884 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2885 LOGD("set platform default format");
2886 dst_format = DEFAULT_PCM_OUT_FORMAT;
2888 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2889 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2892 /* 3. create capsfilter */
2893 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2894 caps = gst_caps_new_simple("audio/x-raw",
2895 "format", G_TYPE_STRING, dst_format,
2896 "rate", G_TYPE_INT, dst_samplerate,
2897 "channels", G_TYPE_INT, dst_channels,
2900 caps_str = gst_caps_to_string(caps);
2901 LOGD("new caps : %s", caps_str);
2903 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2906 gst_caps_unref(caps);
2907 MMPLAYER_FREEIF(caps_str);
2909 /* 4-1. create deinterleave to extract pcm for each channel */
2910 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2911 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2912 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2914 /* audiosink will be added after getting signal for each channel */
2915 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2916 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2917 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2918 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2919 player->no_more_pad = FALSE;
2921 /* 4-2. create fakesink to extract interlevaed pcm */
2922 LOGD("add audio fakesink for interleaved audio");
2923 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2924 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2925 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2926 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2928 _mmplayer_add_signal_connection(player,
2929 G_OBJECT(audiobin[extract_sink_id].gst),
2930 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2932 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2935 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2939 return MM_ERROR_NONE;
2941 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2943 return MM_ERROR_PLAYER_INTERNAL;
2947 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2949 int ret = MM_ERROR_NONE;
2950 mmplayer_gst_element_t *audiobin = NULL;
2951 GList *element_bucket = NULL;
2954 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2955 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2957 audiobin = player->pipeline->audiobin;
2959 if (player->build_audio_offload) { /* skip all the audio filters */
2960 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2962 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2963 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2964 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2966 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2970 /* FIXME: need to mention the supportable condition at API reference */
2971 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2972 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2974 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2976 if (ret != MM_ERROR_NONE)
2979 LOGD("success to make audio bin element");
2980 *bucket = element_bucket;
2983 return MM_ERROR_NONE;
2986 LOGE("failed to make audio bin element");
2987 g_list_free(element_bucket);
2991 return MM_ERROR_PLAYER_INTERNAL;
2995 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2997 mmplayer_gst_element_t *first_element = NULL;
2998 mmplayer_gst_element_t *audiobin = NULL;
3000 GstPad *ghostpad = NULL;
3001 GList *element_bucket = NULL;
3005 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3008 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3010 LOGE("failed to allocate memory for audiobin");
3011 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3015 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3016 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3017 if (!audiobin[MMPLAYER_A_BIN].gst) {
3018 LOGE("failed to create audiobin");
3023 player->pipeline->audiobin = audiobin;
3025 /* create audio filters and audiosink */
3026 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3029 /* adding created elements to bin */
3030 LOGD("adding created elements to bin");
3031 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3034 /* linking elements in the bucket by added order. */
3035 LOGD("Linking elements in the bucket by added order.");
3036 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3039 /* get first element's sinkpad for creating ghostpad */
3040 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3041 if (!first_element) {
3042 LOGE("failed to get first elem");
3046 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3048 LOGE("failed to get pad from first element of audiobin");
3052 ghostpad = gst_ghost_pad_new("sink", pad);
3054 LOGE("failed to create ghostpad");
3058 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3059 LOGE("failed to add ghostpad to audiobin");
3063 gst_object_unref(pad);
3065 g_list_free(element_bucket);
3068 return MM_ERROR_NONE;
3071 LOGD("ERROR : releasing audiobin");
3074 gst_object_unref(GST_OBJECT(pad));
3077 gst_object_unref(GST_OBJECT(ghostpad));
3080 g_list_free(element_bucket);
3082 /* release element which are not added to bin */
3083 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3084 /* NOTE : skip bin */
3085 if (audiobin[i].gst) {
3086 GstObject *parent = NULL;
3087 parent = gst_element_get_parent(audiobin[i].gst);
3090 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3091 audiobin[i].gst = NULL;
3093 gst_object_unref(GST_OBJECT(parent));
3097 /* release audiobin with it's childs */
3098 if (audiobin[MMPLAYER_A_BIN].gst)
3099 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3101 MMPLAYER_FREEIF(audiobin);
3103 player->pipeline->audiobin = NULL;
3105 return MM_ERROR_PLAYER_INTERNAL;
3109 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3111 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3115 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3117 int ret = MM_ERROR_NONE;
3119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3120 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3122 MMPLAYER_VIDEO_BO_LOCK(player);
3124 if (player->video_bo_list) {
3125 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3126 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3127 if (tmp && tmp->bo == bo) {
3129 LOGD("release bo %p", bo);
3130 tbm_bo_unref(tmp->bo);
3131 MMPLAYER_VIDEO_BO_UNLOCK(player);
3132 MMPLAYER_VIDEO_BO_SIGNAL(player);
3137 /* hw codec is running or the list was reset for DRC. */
3138 LOGW("there is no bo list.");
3140 MMPLAYER_VIDEO_BO_UNLOCK(player);
3142 LOGW("failed to find bo %p", bo);
3147 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3152 MMPLAYER_RETURN_IF_FAIL(player);
3154 MMPLAYER_VIDEO_BO_LOCK(player);
3155 if (player->video_bo_list) {
3156 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3157 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3158 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3161 tbm_bo_unref(tmp->bo);
3165 g_list_free(player->video_bo_list);
3166 player->video_bo_list = NULL;
3168 player->video_bo_size = 0;
3169 MMPLAYER_VIDEO_BO_UNLOCK(player);
3176 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3179 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3180 gboolean ret = TRUE;
3182 /* check DRC, if it is, destroy the prev bo list to create again */
3183 if (player->video_bo_size != size) {
3184 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3185 __mmplayer_video_stream_destroy_bo_list(player);
3186 player->video_bo_size = size;
3189 MMPLAYER_VIDEO_BO_LOCK(player);
3191 if ((!player->video_bo_list) ||
3192 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3194 /* create bo list */
3196 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3198 if (player->video_bo_list) {
3199 /* if bo list did not created all, try it again. */
3200 idx = g_list_length(player->video_bo_list);
3201 LOGD("bo list exist(len: %d)", idx);
3204 for (; idx < player->ini.num_of_video_bo; idx++) {
3205 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3207 LOGE("Fail to alloc bo_info.");
3210 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3212 LOGE("Fail to tbm_bo_alloc.");
3213 MMPLAYER_FREEIF(bo_info);
3216 bo_info->used = FALSE;
3217 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3220 /* update video num buffers */
3221 LOGD("video_num_buffers : %d", idx);
3222 mm_player_set_attribute((MMHandleType)player, NULL,
3223 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3224 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3228 MMPLAYER_VIDEO_BO_UNLOCK(player);
3234 /* get bo from list*/
3235 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3236 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3237 if (tmp && (tmp->used == FALSE)) {
3238 LOGD("found bo %p to use", tmp->bo);
3240 MMPLAYER_VIDEO_BO_UNLOCK(player);
3241 return tbm_bo_ref(tmp->bo);
3245 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3246 MMPLAYER_VIDEO_BO_UNLOCK(player);
3250 if (player->ini.video_bo_timeout <= 0) {
3251 MMPLAYER_VIDEO_BO_WAIT(player);
3253 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3254 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3261 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3263 mmplayer_t *player = (mmplayer_t *)data;
3265 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3267 /* send prerolled pkt */
3268 player->video_stream_prerolled = false;
3270 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3272 /* not to send prerolled pkt again */
3273 player->video_stream_prerolled = true;
3277 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3279 mmplayer_t *player = (mmplayer_t *)data;
3280 mmplayer_video_decoded_data_info_t *stream = NULL;
3281 GstMemory *mem = NULL;
3284 MMPLAYER_RETURN_IF_FAIL(player);
3285 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3287 if (player->video_stream_prerolled) {
3288 player->video_stream_prerolled = false;
3289 LOGD("skip the prerolled pkt not to send it again");
3293 /* clear stream data structure */
3294 stream = __mmplayer_create_stream_from_pad(pad);
3296 LOGE("failed to alloc stream");
3300 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3302 /* set size and timestamp */
3303 mem = gst_buffer_peek_memory(buffer, 0);
3304 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3305 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3307 /* check zero-copy */
3308 if (player->set_mode.video_zc &&
3309 player->set_mode.video_export &&
3310 gst_is_tizen_memory(mem)) {
3311 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3312 stream->internal_buffer = gst_buffer_ref(buffer);
3313 } else { /* sw codec */
3314 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3317 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3321 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3322 LOGE("failed to send video decoded data.");
3329 LOGE("release video stream resource.");
3330 if (gst_is_tizen_memory(mem)) {
3332 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3334 tbm_bo_unref(stream->bo[i]);
3337 /* unref gst buffer */
3338 if (stream->internal_buffer)
3339 gst_buffer_unref(stream->internal_buffer);
3342 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3344 MMPLAYER_FREEIF(stream);
3349 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3351 mmplayer_gst_element_t *videobin = NULL;
3354 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3356 videobin = player->pipeline->videobin;
3358 /* Set spatial media metadata and/or user settings to the element.
3360 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3361 "projection-type", player->video360_metadata.projection_type, NULL);
3363 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3364 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3366 if (player->video360_metadata.full_pano_width_pixels &&
3367 player->video360_metadata.full_pano_height_pixels &&
3368 player->video360_metadata.cropped_area_image_width &&
3369 player->video360_metadata.cropped_area_image_height) {
3370 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3371 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3372 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3373 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3374 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3375 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3376 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3380 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3381 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3382 "horizontal-fov", player->video360_horizontal_fov,
3383 "vertical-fov", player->video360_vertical_fov, NULL);
3386 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3387 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3388 "zoom", 1.0f / player->video360_zoom, NULL);
3391 if (player->video360_yaw_radians <= M_PI &&
3392 player->video360_yaw_radians >= -M_PI &&
3393 player->video360_pitch_radians <= M_PI_2 &&
3394 player->video360_pitch_radians >= -M_PI_2) {
3395 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3396 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3397 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3398 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3399 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400 "pose-yaw", player->video360_metadata.init_view_heading,
3401 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3404 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3405 "passthrough", !player->is_video360_enabled, NULL);
3412 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3414 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3415 GList *element_bucket = NULL;
3418 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3420 /* create video360 filter */
3421 if (player->is_360_feature_enabled && player->is_content_spherical) {
3422 LOGD("create video360 element");
3423 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3424 __mmplayer_gst_set_video360_property(player);
3428 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3429 LOGD("skip creating the videoconv and rotator");
3430 return MM_ERROR_NONE;
3433 /* in case of sw codec & overlay surface type, except 360 playback.
3434 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3435 LOGD("create video converter: %s", video_csc);
3436 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3439 *bucket = element_bucket;
3441 return MM_ERROR_NONE;
3443 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3444 g_list_free(element_bucket);
3448 return MM_ERROR_PLAYER_INTERNAL;
3452 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3454 gchar *factory_name = NULL;
3456 switch (surface_type) {
3457 case MM_DISPLAY_SURFACE_OVERLAY:
3458 if (strlen(player->ini.videosink_element_overlay) > 0)
3459 factory_name = player->ini.videosink_element_overlay;
3461 case MM_DISPLAY_SURFACE_REMOTE:
3462 case MM_DISPLAY_SURFACE_NULL:
3463 if (strlen(player->ini.videosink_element_fake) > 0)
3464 factory_name = player->ini.videosink_element_fake;
3467 LOGE("unidentified surface type");
3471 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3472 return factory_name;
3476 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3478 gchar *factory_name = NULL;
3479 mmplayer_gst_element_t *videobin = NULL;
3484 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3486 videobin = player->pipeline->videobin;
3487 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3489 attrs = MMPLAYER_GET_ATTRS(player);
3491 LOGE("cannot get content attribute");
3492 return MM_ERROR_PLAYER_INTERNAL;
3495 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3496 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3497 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3498 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3499 "use-tbm", use_tbm, NULL);
3502 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3503 return MM_ERROR_PLAYER_INTERNAL;
3505 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3508 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3509 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3512 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3514 LOGD("disable last-sample");
3515 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3518 if (player->set_mode.video_export) {
3520 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3521 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3522 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3524 _mmplayer_add_signal_connection(player,
3525 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3526 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3528 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3531 _mmplayer_add_signal_connection(player,
3532 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3533 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3535 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3539 if (videobin[MMPLAYER_V_SINK].gst) {
3540 GstPad *sink_pad = NULL;
3541 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3543 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3544 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3545 gst_object_unref(GST_OBJECT(sink_pad));
3547 LOGE("failed to get sink pad from videosink");
3551 return MM_ERROR_NONE;
3556 * - video overlay surface(arm/x86) : tizenwlsink
3559 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3562 GList *element_bucket = NULL;
3563 mmplayer_gst_element_t *first_element = NULL;
3564 mmplayer_gst_element_t *videobin = NULL;
3565 gchar *videosink_factory_name = NULL;
3568 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3571 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3573 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3575 player->pipeline->videobin = videobin;
3578 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3579 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3580 if (!videobin[MMPLAYER_V_BIN].gst) {
3581 LOGE("failed to create videobin");
3585 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3588 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3589 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3591 /* additional setting for sink plug-in */
3592 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3593 LOGE("failed to set video property");
3597 /* store it as it's sink element */
3598 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3600 /* adding created elements to bin */
3601 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3602 LOGE("failed to add elements");
3606 /* Linking elements in the bucket by added order */
3607 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3608 LOGE("failed to link elements");
3612 /* get first element's sinkpad for creating ghostpad */
3613 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3614 if (!first_element) {
3615 LOGE("failed to get first element from bucket");
3619 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3621 LOGE("failed to get pad from first element");
3625 /* create ghostpad */
3626 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3627 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3628 LOGE("failed to add ghostpad to videobin");
3631 gst_object_unref(pad);
3633 /* done. free allocated variables */
3634 g_list_free(element_bucket);
3638 return MM_ERROR_NONE;
3641 LOGE("ERROR : releasing videobin");
3642 g_list_free(element_bucket);
3645 gst_object_unref(GST_OBJECT(pad));
3647 /* release videobin with it's childs */
3648 if (videobin[MMPLAYER_V_BIN].gst)
3649 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3651 MMPLAYER_FREEIF(videobin);
3652 player->pipeline->videobin = NULL;
3654 return MM_ERROR_PLAYER_INTERNAL;
3658 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3660 GList *element_bucket = NULL;
3661 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3663 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3664 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3665 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3666 "signal-handoffs", FALSE,
3669 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3670 _mmplayer_add_signal_connection(player,
3671 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3672 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3674 G_CALLBACK(__mmplayer_update_subtitle),
3677 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3678 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3680 if (!player->play_subtitle) {
3681 LOGD("add textbin sink as sink element of whole pipeline.");
3682 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3685 /* adding created elements to bin */
3686 LOGD("adding created elements to bin");
3687 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3688 LOGE("failed to add elements");
3692 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3693 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3694 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3696 /* linking elements in the bucket by added order. */
3697 LOGD("Linking elements in the bucket by added order.");
3698 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3699 LOGE("failed to link elements");
3703 /* done. free allocated variables */
3704 g_list_free(element_bucket);
3706 if (textbin[MMPLAYER_T_QUEUE].gst) {
3708 GstPad *ghostpad = NULL;
3710 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3712 LOGE("failed to get sink pad of text queue");
3716 ghostpad = gst_ghost_pad_new("text_sink", pad);
3717 gst_object_unref(pad);
3720 LOGE("failed to create ghostpad of textbin");
3724 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3725 LOGE("failed to add ghostpad to textbin");
3726 gst_object_unref(ghostpad);
3731 return MM_ERROR_NONE;
3734 g_list_free(element_bucket);
3736 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3737 LOGE("remove textbin sink from sink list");
3738 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3741 /* release element at __mmplayer_gst_create_text_sink_bin */
3742 return MM_ERROR_PLAYER_INTERNAL;
3746 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3748 mmplayer_gst_element_t *textbin = NULL;
3749 GList *element_bucket = NULL;
3750 int surface_type = 0;
3755 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3758 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3760 LOGE("failed to allocate memory for textbin");
3761 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3765 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3766 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3767 if (!textbin[MMPLAYER_T_BIN].gst) {
3768 LOGE("failed to create textbin");
3773 player->pipeline->textbin = textbin;
3776 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3777 LOGD("surface type for subtitle : %d", surface_type);
3778 switch (surface_type) {
3779 case MM_DISPLAY_SURFACE_OVERLAY:
3780 case MM_DISPLAY_SURFACE_NULL:
3781 case MM_DISPLAY_SURFACE_REMOTE:
3782 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3783 LOGE("failed to make plain text elements");
3794 return MM_ERROR_NONE;
3798 LOGD("ERROR : releasing textbin");
3800 g_list_free(element_bucket);
3802 /* release signal */
3803 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3805 /* release element which are not added to bin */
3806 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3807 /* NOTE : skip bin */
3808 if (textbin[i].gst) {
3809 GstObject *parent = NULL;
3810 parent = gst_element_get_parent(textbin[i].gst);
3813 gst_object_unref(GST_OBJECT(textbin[i].gst));
3814 textbin[i].gst = NULL;
3816 gst_object_unref(GST_OBJECT(parent));
3821 /* release textbin with it's childs */
3822 if (textbin[MMPLAYER_T_BIN].gst)
3823 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3825 MMPLAYER_FREEIF(textbin);
3826 player->pipeline->textbin = NULL;
3829 return MM_ERROR_PLAYER_INTERNAL;
3833 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3835 mmplayer_gst_element_t *mainbin = NULL;
3836 mmplayer_gst_element_t *textbin = NULL;
3837 MMHandleType attrs = 0;
3838 GstElement *subsrc = NULL;
3839 GstElement *subparse = NULL;
3840 gchar *subtitle_uri = NULL;
3841 const gchar *charset = NULL;
3847 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3849 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3851 mainbin = player->pipeline->mainbin;
3853 attrs = MMPLAYER_GET_ATTRS(player);
3855 LOGE("cannot get content attribute");
3856 return MM_ERROR_PLAYER_INTERNAL;
3859 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3860 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3861 LOGE("subtitle uri is not proper filepath.");
3862 return MM_ERROR_PLAYER_INVALID_URI;
3865 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3866 LOGE("failed to get storage info of subtitle path");
3867 return MM_ERROR_PLAYER_INVALID_URI;
3870 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3872 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3873 player->subtitle_language_list = NULL;
3874 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3876 /* create the subtitle source */
3877 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3879 LOGE("failed to create filesrc element");
3882 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3884 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3885 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3887 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3888 LOGW("failed to add queue");
3889 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3890 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3891 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3896 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3898 LOGE("failed to create subparse element");
3902 charset = _mmplayer_get_charset(subtitle_uri);
3904 LOGD("detected charset is %s", charset);
3905 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3908 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3909 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3911 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3912 LOGW("failed to add subparse");
3913 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3914 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3915 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3919 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3920 LOGW("failed to link subsrc and subparse");
3924 player->play_subtitle = TRUE;
3925 player->adjust_subtitle_pos = 0;
3927 LOGD("play subtitle using subtitle file");
3929 if (player->pipeline->textbin == NULL) {
3930 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3931 LOGE("failed to create text sink bin. continuing without text");
3935 textbin = player->pipeline->textbin;
3937 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3938 LOGW("failed to add textbin");
3940 /* release signal */
3941 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3943 /* release textbin with it's childs */
3944 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3945 MMPLAYER_FREEIF(player->pipeline->textbin);
3946 player->pipeline->textbin = textbin = NULL;
3950 LOGD("link text input selector and textbin ghost pad");
3952 player->textsink_linked = 1;
3953 player->external_text_idx = 0;
3954 LOGI("textsink is linked");
3956 textbin = player->pipeline->textbin;
3957 LOGD("text bin has been created. reuse it.");
3958 player->external_text_idx = 1;
3961 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3962 LOGW("failed to link subparse and textbin");
3966 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3968 LOGE("failed to get sink pad from textsink to probe data");
3972 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3973 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3975 gst_object_unref(pad);
3978 /* create dot. for debugging */
3979 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3982 return MM_ERROR_NONE;
3985 /* release text pipeline resource */
3986 player->textsink_linked = 0;
3988 /* release signal */
3989 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3991 if (player->pipeline->textbin) {
3992 LOGE("remove textbin");
3994 /* release textbin with it's childs */
3995 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3996 MMPLAYER_FREEIF(player->pipeline->textbin);
3997 player->pipeline->textbin = NULL;
4001 /* release subtitle elem */
4002 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4003 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4005 return MM_ERROR_PLAYER_INTERNAL;
4009 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4011 mmplayer_t *player = (mmplayer_t *)data;
4012 MMMessageParamType msg = {0, };
4013 GstClockTime duration = 0;
4014 gpointer text = NULL;
4015 guint text_size = 0;
4016 gboolean ret = TRUE;
4017 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4021 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4022 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4024 if (player->is_subtitle_force_drop) {
4025 LOGW("subtitle is dropped forcedly.");
4029 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4030 text = mapinfo.data;
4031 text_size = mapinfo.size;
4033 if (player->set_mode.subtitle_off) {
4034 LOGD("subtitle is OFF.");
4038 if (!text || (text_size == 0)) {
4039 LOGD("There is no subtitle to be displayed.");
4043 msg.data = (void *)text;
4045 duration = GST_BUFFER_DURATION(buffer);
4047 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4048 if (player->duration > GST_BUFFER_PTS(buffer))
4049 duration = player->duration - GST_BUFFER_PTS(buffer);
4052 LOGI("subtitle duration is invalid, subtitle duration change "
4053 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4055 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4057 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4059 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4060 gst_buffer_unmap(buffer, &mapinfo);
4067 static GstPadProbeReturn
4068 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4070 mmplayer_t *player = (mmplayer_t *)u_data;
4071 GstClockTime cur_timestamp = 0;
4072 gint64 adjusted_timestamp = 0;
4073 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4075 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4077 if (player->set_mode.subtitle_off) {
4078 LOGD("subtitle is OFF.");
4082 if (player->adjust_subtitle_pos == 0) {
4083 LOGD("nothing to do");
4087 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4088 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4090 if (adjusted_timestamp < 0) {
4091 LOGD("adjusted_timestamp under zero");
4096 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4097 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4098 GST_TIME_ARGS(cur_timestamp),
4099 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4101 return GST_PAD_PROBE_OK;
4105 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4109 /* check player and subtitlebin are created */
4110 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4111 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4113 if (position == 0) {
4114 LOGD("nothing to do");
4116 return MM_ERROR_NONE;
4119 /* check current postion */
4120 player->adjust_subtitle_pos = position;
4122 LOGD("save adjust_subtitle_pos in player");
4126 return MM_ERROR_NONE;
4130 * This function is to create audio or video pipeline for playing.
4132 * @param player [in] handle of player
4134 * @return This function returns zero on success.
4139 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4141 int ret = MM_ERROR_NONE;
4142 mmplayer_gst_element_t *mainbin = NULL;
4143 MMHandleType attrs = 0;
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 /* get profile attribute */
4149 attrs = MMPLAYER_GET_ATTRS(player);
4151 LOGE("failed to get content attribute");
4155 /* create pipeline handles */
4156 if (player->pipeline) {
4157 LOGE("pipeline should be released before create new one");
4161 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4163 /* create mainbin */
4164 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4165 if (mainbin == NULL)
4168 /* create pipeline */
4169 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4170 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4171 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4172 LOGE("failed to create pipeline");
4177 player->pipeline->mainbin = mainbin;
4179 /* create the source and decoder elements */
4180 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4181 ret = _mmplayer_gst_build_es_pipeline(player);
4183 if (MMPLAYER_USE_DECODEBIN(player))
4184 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4186 ret = _mmplayer_gst_build_pipeline_with_src(player);
4189 if (ret != MM_ERROR_NONE) {
4190 LOGE("failed to create some elements");
4194 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4195 if (__mmplayer_check_subtitle(player)
4196 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4197 LOGE("failed to create text pipeline");
4200 ret = _mmplayer_gst_add_bus_watch(player);
4201 if (ret != MM_ERROR_NONE) {
4202 LOGE("failed to add bus watch");
4207 return MM_ERROR_NONE;
4210 _mmplayer_bus_watcher_remove(player);
4211 __mmplayer_gst_destroy_pipeline(player);
4212 return MM_ERROR_PLAYER_INTERNAL;
4216 __mmplayer_reset_gapless_state(mmplayer_t *player)
4219 MMPLAYER_RETURN_IF_FAIL(player
4221 && player->pipeline->audiobin
4222 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4224 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4231 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4234 int ret = MM_ERROR_NONE;
4238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4240 /* cleanup stuffs */
4241 MMPLAYER_FREEIF(player->type);
4242 player->no_more_pad = FALSE;
4243 player->num_dynamic_pad = 0;
4245 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4246 player->subtitle_language_list = NULL;
4247 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4249 MMPLAYER_RECONFIGURE_LOCK(player);
4250 __mmplayer_reset_gapless_state(player);
4251 MMPLAYER_RECONFIGURE_UNLOCK(player);
4253 if (player->streamer) {
4254 _mm_player_streaming_initialize(player->streamer, FALSE);
4255 _mm_player_streaming_destroy(player->streamer);
4256 player->streamer = NULL;
4259 /* cleanup unlinked mime type */
4260 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4261 MMPLAYER_FREEIF(player->unlinked_video_mime);
4262 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4264 /* cleanup running stuffs */
4265 _mmplayer_cancel_eos_timer(player);
4267 /* cleanup gst stuffs */
4268 if (player->pipeline) {
4269 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4270 GstTagList *tag_list = player->pipeline->tag_list;
4272 /* first we need to disconnect all signal hander */
4273 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4276 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4277 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4278 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4279 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4280 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4281 gst_object_unref(bus);
4283 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4284 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4285 if (ret != MM_ERROR_NONE) {
4286 LOGE("fail to change state to NULL");
4287 return MM_ERROR_PLAYER_INTERNAL;
4290 LOGW("succeeded in changing state to NULL");
4292 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4295 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4296 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4298 /* free avsysaudiosink
4299 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4300 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4302 MMPLAYER_FREEIF(audiobin);
4303 MMPLAYER_FREEIF(videobin);
4304 MMPLAYER_FREEIF(textbin);
4305 MMPLAYER_FREEIF(mainbin);
4309 gst_tag_list_unref(tag_list);
4311 MMPLAYER_FREEIF(player->pipeline);
4313 MMPLAYER_FREEIF(player->album_art);
4315 if (player->v_stream_caps) {
4316 gst_caps_unref(player->v_stream_caps);
4317 player->v_stream_caps = NULL;
4320 if (player->a_stream_caps) {
4321 gst_caps_unref(player->a_stream_caps);
4322 player->a_stream_caps = NULL;
4325 if (player->s_stream_caps) {
4326 gst_caps_unref(player->s_stream_caps);
4327 player->s_stream_caps = NULL;
4329 _mmplayer_track_destroy(player);
4331 if (player->sink_elements)
4332 g_list_free(player->sink_elements);
4333 player->sink_elements = NULL;
4335 if (player->bufmgr) {
4336 tbm_bufmgr_deinit(player->bufmgr);
4337 player->bufmgr = NULL;
4340 LOGW("finished destroy pipeline");
4348 __mmplayer_gst_realize(mmplayer_t *player)
4351 int ret = MM_ERROR_NONE;
4355 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4357 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4359 ret = __mmplayer_gst_create_pipeline(player);
4361 LOGE("failed to create pipeline");
4365 /* set pipeline state to READY */
4366 /* NOTE : state change to READY must be performed sync. */
4367 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4368 ret = _mmplayer_gst_set_state(player,
4369 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4371 if (ret != MM_ERROR_NONE) {
4372 /* return error if failed to set state */
4373 LOGE("failed to set READY state");
4377 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4379 /* create dot before error-return. for debugging */
4380 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4388 __mmplayer_gst_unrealize(mmplayer_t *player)
4390 int ret = MM_ERROR_NONE;
4394 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4396 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4397 MMPLAYER_PRINT_STATE(player);
4399 /* release miscellaneous information */
4400 __mmplayer_release_misc(player);
4402 /* destroy pipeline */
4403 ret = __mmplayer_gst_destroy_pipeline(player);
4404 if (ret != MM_ERROR_NONE) {
4405 LOGE("failed to destory pipeline");
4409 /* release miscellaneous information.
4410 these info needs to be released after pipeline is destroyed. */
4411 __mmplayer_release_misc_post(player);
4413 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4421 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4426 LOGW("set_message_callback is called with invalid player handle");
4427 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4430 player->msg_cb = callback;
4431 player->msg_cb_param = user_param;
4433 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4437 return MM_ERROR_NONE;
4441 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4443 int ret = MM_ERROR_NONE;
4448 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4449 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4450 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4452 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4454 if (strstr(uri, "es_buff://")) {
4455 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4456 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4457 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4458 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4460 tmp = g_ascii_strdown(uri, strlen(uri));
4461 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4462 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4464 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4466 } else if (strstr(uri, "mms://")) {
4467 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4468 } else if ((path = strstr(uri, "mem://"))) {
4469 ret = __mmplayer_set_mem_uri(data, path, param);
4471 ret = __mmplayer_set_file_uri(data, uri);
4474 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4475 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4476 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4477 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4479 /* dump parse result */
4480 SECURE_LOGW("incoming uri : %s", uri);
4481 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4482 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4490 __mmplayer_can_do_interrupt(mmplayer_t *player)
4492 if (!player || !player->pipeline || !player->attrs) {
4493 LOGW("not initialized");
4497 if (player->audio_decoded_cb) {
4498 LOGW("not support in pcm extraction mode");
4502 /* check if seeking */
4503 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4504 MMMessageParamType msg_param;
4505 memset(&msg_param, 0, sizeof(MMMessageParamType));
4506 msg_param.code = MM_ERROR_PLAYER_SEEK;
4507 player->seek_state = MMPLAYER_SEEK_NONE;
4508 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4512 /* check other thread */
4513 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4514 LOGW("locked already, cmd state : %d", player->cmd);
4516 /* check application command */
4517 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4518 LOGW("playing.. should wait cmd lock then, will be interrupted");
4520 /* lock will be released at mrp_resource_release_cb() */
4521 MMPLAYER_CMD_LOCK(player);
4524 LOGW("nothing to do");
4527 LOGW("can interrupt immediately");
4531 FAILED: /* with CMD UNLOCKED */
4534 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4539 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4542 mmplayer_t *player = NULL;
4543 MMMessageParamType msg = {0, };
4545 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4550 LOGE("user_data is null");
4553 player = (mmplayer_t *)user_data;
4555 if (!__mmplayer_can_do_interrupt(player)) {
4556 LOGW("no need to interrupt, so leave");
4557 /* FIXME: there is no way to avoid releasing resource. */
4561 player->interrupted_by_resource = TRUE;
4563 /* get last play position */
4564 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4565 msg.union_type = MM_MSG_UNION_TIME;
4566 msg.time.elapsed = pos;
4567 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4569 LOGW("failed to get play position.");
4572 LOGD("video resource conflict so, resource will be freed by unrealizing");
4573 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4574 LOGE("failed to unrealize");
4576 /* lock is called in __mmplayer_can_do_interrupt() */
4577 MMPLAYER_CMD_UNLOCK(player);
4579 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4580 player->hw_resource[res_idx] = NULL;
4584 return TRUE; /* release all the resources */
4588 __mmplayer_initialize_video_roi(mmplayer_t *player)
4590 player->video_roi.scale_x = 0.0;
4591 player->video_roi.scale_y = 0.0;
4592 player->video_roi.scale_width = 1.0;
4593 player->video_roi.scale_height = 1.0;
4597 _mmplayer_create_player(MMHandleType handle)
4599 int ret = MM_ERROR_PLAYER_INTERNAL;
4600 bool enabled = false;
4602 mmplayer_t *player = MM_PLAYER_CAST(handle);
4606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4608 /* initialize player state */
4609 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4610 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4611 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4612 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4614 /* check current state */
4615 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4617 /* construct attributes */
4618 player->attrs = _mmplayer_construct_attribute(handle);
4620 if (!player->attrs) {
4621 LOGE("Failed to construct attributes");
4625 /* initialize gstreamer with configured parameter */
4626 if (!__mmplayer_init_gstreamer(player)) {
4627 LOGE("Initializing gstreamer failed");
4628 _mmplayer_deconstruct_attribute(handle);
4632 /* create lock. note that g_tread_init() has already called in gst_init() */
4633 g_mutex_init(&player->fsink_lock);
4635 /* create update tag lock */
4636 g_mutex_init(&player->update_tag_lock);
4638 /* create gapless play mutex */
4639 g_mutex_init(&player->gapless_play_thread_mutex);
4641 /* create gapless play cond */
4642 g_cond_init(&player->gapless_play_thread_cond);
4644 /* create gapless play thread */
4645 player->gapless_play_thread =
4646 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4647 if (!player->gapless_play_thread) {
4648 LOGE("failed to create gapless play thread");
4649 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4650 g_mutex_clear(&player->gapless_play_thread_mutex);
4651 g_cond_clear(&player->gapless_play_thread_cond);
4655 player->bus_msg_q = g_queue_new();
4656 if (!player->bus_msg_q) {
4657 LOGE("failed to create queue for bus_msg");
4658 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4662 ret = _mmplayer_initialize_video_capture(player);
4663 if (ret != MM_ERROR_NONE) {
4664 LOGE("failed to initialize video capture");
4668 /* initialize resource manager */
4669 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4670 __resource_release_cb, player, &player->resource_manager)
4671 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4672 LOGE("failed to initialize resource manager");
4673 ret = MM_ERROR_PLAYER_INTERNAL;
4677 /* create video bo lock and cond */
4678 g_mutex_init(&player->video_bo_mutex);
4679 g_cond_init(&player->video_bo_cond);
4681 /* create subtitle info lock and cond */
4682 g_mutex_init(&player->subtitle_info_mutex);
4683 g_cond_init(&player->subtitle_info_cond);
4685 player->streaming_type = STREAMING_SERVICE_NONE;
4687 /* give default value of audio effect setting */
4688 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4689 player->sound.rg_enable = false;
4690 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4692 player->play_subtitle = FALSE;
4693 player->has_closed_caption = FALSE;
4694 player->pending_resume = FALSE;
4695 if (player->ini.dump_element_keyword[0][0] == '\0')
4696 player->ini.set_dump_element_flag = FALSE;
4698 player->ini.set_dump_element_flag = TRUE;
4700 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4701 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4702 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4704 /* Set video360 settings to their defaults for just-created player.
4707 player->is_360_feature_enabled = FALSE;
4708 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4709 LOGI("spherical feature info: %d", enabled);
4711 player->is_360_feature_enabled = TRUE;
4713 LOGE("failed to get spherical feature info");
4716 player->is_content_spherical = FALSE;
4717 player->is_video360_enabled = TRUE;
4718 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4719 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4720 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4721 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4722 player->video360_zoom = 1.0f;
4723 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4724 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4726 __mmplayer_initialize_video_roi(player);
4728 /* set player state to null */
4729 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4730 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4734 return MM_ERROR_NONE;
4738 g_mutex_clear(&player->fsink_lock);
4739 /* free update tag lock */
4740 g_mutex_clear(&player->update_tag_lock);
4741 g_queue_free(player->bus_msg_q);
4742 player->bus_msg_q = NULL;
4743 /* free gapless play thread */
4744 if (player->gapless_play_thread) {
4745 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4746 player->gapless_play_thread_exit = TRUE;
4747 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4748 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4750 g_thread_join(player->gapless_play_thread);
4751 player->gapless_play_thread = NULL;
4753 g_mutex_clear(&player->gapless_play_thread_mutex);
4754 g_cond_clear(&player->gapless_play_thread_cond);
4757 /* release attributes */
4758 _mmplayer_deconstruct_attribute(handle);
4766 __mmplayer_init_gstreamer(mmplayer_t *player)
4768 static gboolean initialized = FALSE;
4769 static const int max_argc = 50;
4771 gchar **argv = NULL;
4772 gchar **argv2 = NULL;
4778 LOGD("gstreamer already initialized.");
4783 argc = malloc(sizeof(int));
4784 argv = malloc(sizeof(gchar *) * max_argc);
4785 argv2 = malloc(sizeof(gchar *) * max_argc);
4787 if (!argc || !argv || !argv2)
4790 memset(argv, 0, sizeof(gchar *) * max_argc);
4791 memset(argv2, 0, sizeof(gchar *) * max_argc);
4795 argv[0] = g_strdup("mmplayer");
4798 for (i = 0; i < 5; i++) {
4799 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4800 if (strlen(player->ini.gst_param[i]) > 0) {
4801 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4806 /* we would not do fork for scanning plugins */
4807 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4810 /* check disable registry scan */
4811 if (player->ini.skip_rescan) {
4812 argv[*argc] = g_strdup("--gst-disable-registry-update");
4816 /* check disable segtrap */
4817 if (player->ini.disable_segtrap) {
4818 argv[*argc] = g_strdup("--gst-disable-segtrap");
4822 LOGD("initializing gstreamer with following parameter");
4823 LOGD("argc : %d", *argc);
4826 for (i = 0; i < arg_count; i++) {
4828 LOGD("argv[%d] : %s", i, argv2[i]);
4831 /* initializing gstreamer */
4832 if (!gst_init_check(argc, &argv, &err)) {
4833 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4840 for (i = 0; i < arg_count; i++) {
4842 LOGD("release - argv[%d] : %s", i, argv2[i]);
4844 MMPLAYER_FREEIF(argv2[i]);
4847 MMPLAYER_FREEIF(argv);
4848 MMPLAYER_FREEIF(argv2);
4849 MMPLAYER_FREEIF(argc);
4859 for (i = 0; i < arg_count; i++) {
4860 LOGD("free[%d] : %s", i, argv2[i]);
4861 MMPLAYER_FREEIF(argv2[i]);
4864 MMPLAYER_FREEIF(argv);
4865 MMPLAYER_FREEIF(argv2);
4866 MMPLAYER_FREEIF(argc);
4872 __mmplayer_check_async_state_transition(mmplayer_t *player)
4874 GstState element_state = GST_STATE_VOID_PENDING;
4875 GstState element_pending_state = GST_STATE_VOID_PENDING;
4876 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4877 GstElement *element = NULL;
4878 gboolean async = FALSE;
4880 /* check player handle */
4881 MMPLAYER_RETURN_IF_FAIL(player &&
4883 player->pipeline->mainbin &&
4884 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4887 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4889 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4890 LOGD("don't need to check the pipeline state");
4894 MMPLAYER_PRINT_STATE(player);
4896 /* wait for state transition */
4897 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4898 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4900 if (ret == GST_STATE_CHANGE_FAILURE) {
4901 LOGE(" [%s] state : %s pending : %s",
4902 GST_ELEMENT_NAME(element),
4903 gst_element_state_get_name(element_state),
4904 gst_element_state_get_name(element_pending_state));
4906 /* dump state of all element */
4907 _mmplayer_dump_pipeline_state(player);
4912 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4917 _mmplayer_destroy(MMHandleType handle)
4919 mmplayer_t *player = MM_PLAYER_CAST(handle);
4923 /* check player handle */
4924 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4926 /* destroy can called at anytime */
4927 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4929 /* check async state transition */
4930 __mmplayer_check_async_state_transition(player);
4932 /* release gapless play thread */
4933 if (player->gapless_play_thread) {
4934 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4935 player->gapless_play_thread_exit = TRUE;
4936 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4937 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4939 LOGD("waitting for gapless play thread exit");
4940 g_thread_join(player->gapless_play_thread);
4941 g_mutex_clear(&player->gapless_play_thread_mutex);
4942 g_cond_clear(&player->gapless_play_thread_cond);
4943 LOGD("gapless play thread released");
4946 _mmplayer_release_video_capture(player);
4948 /* de-initialize resource manager */
4949 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4950 player->resource_manager))
4951 LOGE("failed to deinitialize resource manager");
4953 /* release miscellaneous information */
4954 __mmplayer_release_misc(player);
4956 /* release pipeline */
4957 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4958 LOGE("failed to destory pipeline");
4959 return MM_ERROR_PLAYER_INTERNAL;
4962 g_queue_free(player->bus_msg_q);
4964 /* release subtitle info lock and cond */
4965 g_mutex_clear(&player->subtitle_info_mutex);
4966 g_cond_clear(&player->subtitle_info_cond);
4968 __mmplayer_release_dump_list(player->dump_list);
4970 /* release miscellaneous information.
4971 these info needs to be released after pipeline is destroyed. */
4972 __mmplayer_release_misc_post(player);
4974 /* release attributes */
4975 _mmplayer_deconstruct_attribute(handle);
4977 if (player->uri_info.uri_list) {
4978 GList *uri_list = player->uri_info.uri_list;
4979 for (; uri_list; uri_list = g_list_next(uri_list)) {
4980 gchar *uri = uri_list->data;
4981 MMPLAYER_FREEIF(uri);
4983 g_list_free(player->uri_info.uri_list);
4984 player->uri_info.uri_list = NULL;
4988 g_mutex_clear(&player->fsink_lock);
4991 g_mutex_clear(&player->update_tag_lock);
4993 /* release video bo lock and cond */
4994 g_mutex_clear(&player->video_bo_mutex);
4995 g_cond_clear(&player->video_bo_cond);
4999 return MM_ERROR_NONE;
5003 _mmplayer_realize(MMHandleType hplayer)
5005 mmplayer_t *player = (mmplayer_t *)hplayer;
5006 int ret = MM_ERROR_NONE;
5009 MMHandleType attrs = 0;
5010 int video_codec_type = 0;
5011 int audio_codec_type = 0;
5012 int default_codec_type = 0;
5015 /* check player handle */
5016 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5018 /* check current state */
5019 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5021 attrs = MMPLAYER_GET_ATTRS(player);
5023 LOGE("fail to get attributes.");
5024 return MM_ERROR_PLAYER_INTERNAL;
5026 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5027 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5029 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5030 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5032 if (ret != MM_ERROR_NONE) {
5033 LOGE("failed to parse profile");
5038 if (uri && (strstr(uri, "es_buff://"))) {
5039 if (strstr(uri, "es_buff://push_mode"))
5040 player->es_player_push_mode = TRUE;
5042 player->es_player_push_mode = FALSE;
5045 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5046 LOGW("mms protocol is not supported format.");
5047 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5050 if (MMPLAYER_IS_STREAMING(player))
5051 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5053 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5055 player->smooth_streaming = FALSE;
5056 player->videodec_linked = 0;
5057 player->audiodec_linked = 0;
5058 player->textsink_linked = 0;
5059 player->is_external_subtitle_present = FALSE;
5060 player->is_external_subtitle_added_now = FALSE;
5061 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5062 player->video360_metadata.is_spherical = -1;
5063 player->is_openal_plugin_used = FALSE;
5064 player->subtitle_language_list = NULL;
5065 player->is_subtitle_force_drop = FALSE;
5067 _mmplayer_track_initialize(player);
5068 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5070 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5071 gint prebuffer_ms = 0, rebuffer_ms = 0;
5073 player->streamer = _mm_player_streaming_create();
5074 _mm_player_streaming_initialize(player->streamer, TRUE);
5076 mm_attrs_multiple_get(player->attrs, NULL,
5077 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5078 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5080 if (prebuffer_ms > 0) {
5081 prebuffer_ms = MAX(prebuffer_ms, 1000);
5082 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5085 if (rebuffer_ms > 0) {
5086 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5087 rebuffer_ms = MAX(rebuffer_ms, 1000);
5088 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5091 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5092 player->streamer->buffering_req.rebuffer_time);
5095 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5096 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5097 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5099 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5101 if (audio_codec_type != default_codec_type) {
5102 LOGD("audio dec sorting is required");
5103 player->need_audio_dec_sorting = TRUE;
5106 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5107 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5108 LOGD("video dec sorting is required");
5109 player->need_video_dec_sorting = TRUE;
5112 /* realize pipeline */
5113 ret = __mmplayer_gst_realize(player);
5114 if (ret != MM_ERROR_NONE)
5115 LOGE("fail to realize the player.");
5117 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5125 _mmplayer_unrealize(MMHandleType hplayer)
5127 mmplayer_t *player = (mmplayer_t *)hplayer;
5128 int ret = MM_ERROR_NONE;
5132 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5134 MMPLAYER_CMD_UNLOCK(player);
5135 _mmplayer_bus_watcher_remove(player);
5136 /* destroy the gst bus msg thread which is created during realize.
5137 this funct have to be called before getting cmd lock. */
5138 _mmplayer_bus_msg_thread_destroy(player);
5139 MMPLAYER_CMD_LOCK(player);
5141 /* check current state */
5142 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5144 /* check async state transition */
5145 __mmplayer_check_async_state_transition(player);
5147 /* unrealize pipeline */
5148 ret = __mmplayer_gst_unrealize(player);
5150 if (!player->interrupted_by_resource) {
5151 int rm_ret = MM_ERROR_NONE;
5152 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5154 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5155 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5156 if (rm_ret != MM_ERROR_NONE)
5157 LOGE("failed to release [%d] resources", res_idx);
5166 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5168 mmplayer_t *player = (mmplayer_t *)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5172 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5176 _mmplayer_get_state(MMHandleType hplayer, int *state)
5178 mmplayer_t *player = (mmplayer_t *)hplayer;
5180 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5182 *state = MMPLAYER_CURRENT_STATE(player);
5184 return MM_ERROR_NONE;
5188 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5190 GstElement *vol_element = NULL;
5191 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5195 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5197 /* check pipeline handle */
5198 if (!player->pipeline || !player->pipeline->audiobin) {
5199 LOGD("'%s' will be applied when audiobin is created", prop_name);
5201 /* NOTE : stored value will be used in create_audiobin
5202 * returning MM_ERROR_NONE here makes application to able to
5203 * set audio volume or mute at anytime.
5205 return MM_ERROR_NONE;
5208 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5209 volume_elem_id = MMPLAYER_A_SINK;
5211 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5213 LOGE("failed to get vol element %d", volume_elem_id);
5214 return MM_ERROR_PLAYER_INTERNAL;
5217 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5219 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5220 LOGE("there is no '%s' property", prop_name);
5221 return MM_ERROR_PLAYER_INTERNAL;
5224 if (!strcmp(prop_name, "volume")) {
5225 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5226 } else if (!strcmp(prop_name, "mute")) {
5227 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5229 LOGE("invalid property %s", prop_name);
5230 return MM_ERROR_PLAYER_INTERNAL;
5233 return MM_ERROR_NONE;
5237 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5239 int ret = MM_ERROR_NONE;
5240 mmplayer_t *player = (mmplayer_t *)hplayer;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 LOGD("volume = %f", volume);
5247 /* invalid factor range or not */
5248 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5249 LOGE("Invalid volume value");
5250 return MM_ERROR_INVALID_ARGUMENT;
5253 player->sound.volume = volume;
5255 ret = __mmplayer_gst_set_volume_property(player, "volume");
5262 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5264 mmplayer_t *player = (mmplayer_t *)hplayer;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5269 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5271 *volume = player->sound.volume;
5273 LOGD("current vol = %f", *volume);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5282 int ret = MM_ERROR_NONE;
5283 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 LOGD("mute = %d", mute);
5290 player->sound.mute = mute;
5292 ret = __mmplayer_gst_set_volume_property(player, "mute");
5299 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5301 mmplayer_t *player = (mmplayer_t *)hplayer;
5305 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5306 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5308 *mute = player->sound.mute;
5310 LOGD("current mute = %d", *mute);
5314 return MM_ERROR_NONE;
5318 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5320 mmplayer_t *player = (mmplayer_t *)hplayer;
5324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5326 player->audio_stream_changed_cb = callback;
5327 player->audio_stream_changed_cb_user_param = user_param;
5328 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5332 return MM_ERROR_NONE;
5336 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5338 mmplayer_t *player = (mmplayer_t *)hplayer;
5342 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5344 player->audio_decoded_cb = callback;
5345 player->audio_decoded_cb_user_param = user_param;
5346 player->audio_extract_opt = opt;
5347 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5351 return MM_ERROR_NONE;
5355 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5357 mmplayer_t *player = (mmplayer_t *)hplayer;
5361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5363 if (callback && !player->bufmgr)
5364 player->bufmgr = tbm_bufmgr_init(-1);
5366 player->set_mode.video_export = (callback) ? true : false;
5367 player->video_decoded_cb = callback;
5368 player->video_decoded_cb_user_param = user_param;
5370 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5374 return MM_ERROR_NONE;
5378 _mmplayer_start(MMHandleType hplayer)
5380 mmplayer_t *player = (mmplayer_t *)hplayer;
5381 gint ret = MM_ERROR_NONE;
5385 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5387 /* check current state */
5388 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5390 /* start pipeline */
5391 ret = _mmplayer_gst_start(player);
5392 if (ret != MM_ERROR_NONE)
5393 LOGE("failed to start player.");
5395 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5396 LOGD("force playing start even during buffering");
5397 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5405 /* NOTE: post "not supported codec message" to application
5406 * when one codec is not found during AUTOPLUGGING in MSL.
5407 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5408 * And, if any codec is not found, don't send message here.
5409 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5412 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5414 MMMessageParamType msg_param;
5415 memset(&msg_param, 0, sizeof(MMMessageParamType));
5416 gboolean post_msg_direct = FALSE;
5420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5422 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5423 player->not_supported_codec, player->can_support_codec);
5425 if (player->not_found_demuxer) {
5426 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5429 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5430 MMPLAYER_FREEIF(msg_param.data);
5432 return MM_ERROR_NONE;
5435 if (player->not_supported_codec) {
5436 if (player->can_support_codec) {
5437 // There is one codec to play
5438 post_msg_direct = TRUE;
5440 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5441 post_msg_direct = TRUE;
5444 if (post_msg_direct) {
5445 MMMessageParamType msg_param;
5446 memset(&msg_param, 0, sizeof(MMMessageParamType));
5448 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5449 LOGW("not found AUDIO codec, posting error code to application.");
5451 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5452 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5453 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5454 LOGW("not found VIDEO codec, posting error code to application.");
5456 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5457 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5460 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5462 MMPLAYER_FREEIF(msg_param.data);
5464 return MM_ERROR_NONE;
5466 // no any supported codec case
5467 LOGW("not found any codec, posting error code to application.");
5469 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5470 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5471 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5473 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5474 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5477 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5479 MMPLAYER_FREEIF(msg_param.data);
5485 return MM_ERROR_NONE;
5488 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5490 GstState element_state = GST_STATE_VOID_PENDING;
5491 GstState element_pending_state = GST_STATE_VOID_PENDING;
5492 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5493 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5495 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5497 MMPLAYER_RECONFIGURE_LOCK(player);
5498 if (!player->gapless.reconfigure) {
5499 MMPLAYER_RECONFIGURE_UNLOCK(player);
5503 LOGI("reconfigure is under process");
5504 MMPLAYER_RECONFIGURE_WAIT(player);
5505 MMPLAYER_RECONFIGURE_UNLOCK(player);
5506 LOGI("reconfigure is completed.");
5508 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5509 &element_state, &element_pending_state, timeout * GST_SECOND);
5510 if (result == GST_STATE_CHANGE_FAILURE)
5511 LOGW("failed to get pipeline state in %d sec", timeout);
5516 /* NOTE : it should be able to call 'stop' anytime*/
5518 _mmplayer_stop(MMHandleType hplayer)
5520 mmplayer_t *player = (mmplayer_t *)hplayer;
5521 int ret = MM_ERROR_NONE;
5525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5527 /* check current state */
5528 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5530 /* need to wait till the rebuilding pipeline is completed */
5531 __mmplayer_check_pipeline_reconfigure_state(player);
5532 MMPLAYER_RECONFIGURE_LOCK(player);
5533 __mmplayer_reset_gapless_state(player);
5534 MMPLAYER_RECONFIGURE_UNLOCK(player);
5536 /* NOTE : application should not wait for EOS after calling STOP */
5537 _mmplayer_cancel_eos_timer(player);
5540 player->seek_state = MMPLAYER_SEEK_NONE;
5543 ret = _mmplayer_gst_stop(player);
5545 if (ret != MM_ERROR_NONE)
5546 LOGE("failed to stop player.");
5554 _mmplayer_pause(MMHandleType hplayer)
5556 mmplayer_t *player = (mmplayer_t *)hplayer;
5557 gint64 pos_nsec = 0;
5558 gboolean async = FALSE;
5559 gint ret = MM_ERROR_NONE;
5563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5565 /* check current state */
5566 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5568 /* check pipline reconfigure state */
5569 __mmplayer_check_pipeline_reconfigure_state(player);
5571 switch (MMPLAYER_CURRENT_STATE(player)) {
5572 case MM_PLAYER_STATE_READY:
5574 /* check prepare async or not.
5575 * In the case of streaming playback, it's recommned to avoid blocking wait.
5577 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5578 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5580 /* Changing back sync of rtspsrc to async */
5581 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5582 LOGD("async prepare working mode for rtsp");
5588 case MM_PLAYER_STATE_PLAYING:
5590 /* NOTE : store current point to overcome some bad operation
5591 *(returning zero when getting current position in paused state) of some
5594 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5595 LOGW("getting current position failed in paused");
5597 player->last_position = pos_nsec;
5599 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5600 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5601 This causes problem is position calculation during normal pause resume scenarios also.
5602 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5603 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5604 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5605 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5611 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5612 LOGD("doing async pause in case of ms buff src");
5616 /* pause pipeline */
5617 ret = _mmplayer_gst_pause(player, async);
5619 if (ret != MM_ERROR_NONE)
5620 LOGE("failed to pause player. ret : 0x%x", ret);
5622 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5623 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5624 LOGE("failed to update display_rotation");
5632 /* in case of streaming, pause could take long time.*/
5634 _mmplayer_abort_pause(MMHandleType hplayer)
5636 mmplayer_t *player = (mmplayer_t *)hplayer;
5637 int ret = MM_ERROR_NONE;
5641 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5643 player->pipeline->mainbin,
5644 MM_ERROR_PLAYER_NOT_INITIALIZED);
5646 LOGD("set the pipeline state to READY");
5648 /* set state to READY */
5649 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5650 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5651 if (ret != MM_ERROR_NONE) {
5652 LOGE("fail to change state to READY");
5653 return MM_ERROR_PLAYER_INTERNAL;
5656 LOGD("succeeded in changing state to READY");
5661 _mmplayer_resume(MMHandleType hplayer)
5663 mmplayer_t *player = (mmplayer_t *)hplayer;
5664 int ret = MM_ERROR_NONE;
5665 gboolean async = FALSE;
5669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5671 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5672 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5673 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5677 /* Changing back sync mode rtspsrc to async */
5678 LOGD("async resume for rtsp case");
5682 /* check current state */
5683 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5685 ret = _mmplayer_gst_resume(player, async);
5686 if (ret != MM_ERROR_NONE)
5687 LOGE("failed to resume player.");
5689 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5690 LOGD("force resume even during buffering");
5691 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5700 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5702 mmplayer_t *player = (mmplayer_t *)hplayer;
5703 gint64 pos_nsec = 0;
5704 int ret = MM_ERROR_NONE;
5706 signed long long start = 0, stop = 0;
5707 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5710 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5711 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5713 /* The sound of video is not supported under 0.0 and over 2.0. */
5714 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5715 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5718 _mmplayer_set_mute(hplayer, mute);
5720 if (player->playback_rate == rate)
5721 return MM_ERROR_NONE;
5723 /* If the position is reached at start potion during fast backward, EOS is posted.
5724 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5726 player->playback_rate = rate;
5728 current_state = MMPLAYER_CURRENT_STATE(player);
5730 if (current_state != MM_PLAYER_STATE_PAUSED)
5731 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5733 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5735 if ((current_state == MM_PLAYER_STATE_PAUSED)
5736 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5737 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5738 pos_nsec = player->last_position;
5743 stop = GST_CLOCK_TIME_NONE;
5745 start = GST_CLOCK_TIME_NONE;
5749 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5750 player->playback_rate,
5752 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5753 GST_SEEK_TYPE_SET, start,
5754 GST_SEEK_TYPE_SET, stop)) {
5755 LOGE("failed to set speed playback");
5756 return MM_ERROR_PLAYER_SEEK;
5759 LOGD("succeeded to set speed playback as %0.1f", rate);
5763 return MM_ERROR_NONE;;
5767 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5769 mmplayer_t *player = (mmplayer_t *)hplayer;
5770 int ret = MM_ERROR_NONE;
5774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5776 /* check pipline reconfigure state */
5777 __mmplayer_check_pipeline_reconfigure_state(player);
5779 ret = _mmplayer_gst_set_position(player, position, FALSE);
5787 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5789 mmplayer_t *player = (mmplayer_t *)hplayer;
5790 int ret = MM_ERROR_NONE;
5792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5795 if (g_strrstr(player->type, "video/mpegts"))
5796 __mmplayer_update_duration_value(player);
5798 *duration = player->duration;
5803 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5805 mmplayer_t *player = (mmplayer_t *)hplayer;
5806 int ret = MM_ERROR_NONE;
5808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5810 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5816 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5818 mmplayer_t *player = (mmplayer_t *)hplayer;
5819 int ret = MM_ERROR_NONE;
5823 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5825 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5833 __mmplayer_is_midi_type(gchar *str_caps)
5835 if ((g_strrstr(str_caps, "audio/midi")) ||
5836 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5837 (g_strrstr(str_caps, "application/x-smaf")) ||
5838 (g_strrstr(str_caps, "audio/x-imelody")) ||
5839 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5840 (g_strrstr(str_caps, "audio/xmf")) ||
5841 (g_strrstr(str_caps, "audio/mxmf"))) {
5850 __mmplayer_is_only_mp3_type(gchar *str_caps)
5852 if (g_strrstr(str_caps, "application/x-id3") ||
5853 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5859 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5861 GstStructure *caps_structure = NULL;
5862 gint samplerate = 0;
5866 MMPLAYER_RETURN_IF_FAIL(player && caps);
5868 caps_structure = gst_caps_get_structure(caps, 0);
5870 /* set stream information */
5871 gst_structure_get_int(caps_structure, "rate", &samplerate);
5872 gst_structure_get_int(caps_structure, "channels", &channels);
5874 mm_player_set_attribute((MMHandleType)player, NULL,
5875 "content_audio_samplerate", samplerate,
5876 "content_audio_channels", channels, NULL);
5878 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5882 __mmplayer_update_content_type_info(mmplayer_t *player)
5885 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5887 if (__mmplayer_is_midi_type(player->type)) {
5888 player->bypass_audio_effect = TRUE;
5892 if (!player->streamer) {
5893 LOGD("no need to check streaming type");
5897 if (g_strrstr(player->type, "application/x-hls")) {
5898 /* If it can't know exact type when it parses uri because of redirection case,
5899 * it will be fixed by typefinder or when doing autoplugging.
5901 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5902 player->streamer->is_adaptive_streaming = TRUE;
5903 } else if (g_strrstr(player->type, "application/dash+xml")) {
5904 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5905 player->streamer->is_adaptive_streaming = TRUE;
5908 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5909 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5910 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5912 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5913 if (player->streamer->is_adaptive_streaming)
5914 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5916 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5920 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5925 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5926 GstCaps *caps, gpointer data)
5928 mmplayer_t *player = (mmplayer_t *)data;
5932 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5934 /* store type string */
5935 MMPLAYER_FREEIF(player->type);
5936 player->type = gst_caps_to_string(caps);
5938 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5939 player, player->type, probability, gst_caps_get_size(caps));
5941 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5942 (g_strrstr(player->type, "audio/x-raw-int"))) {
5943 LOGE("not support media format");
5945 if (player->msg_posted == FALSE) {
5946 MMMessageParamType msg_param;
5947 memset(&msg_param, 0, sizeof(MMMessageParamType));
5949 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5950 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5952 /* don't post more if one was sent already */
5953 player->msg_posted = TRUE;
5958 __mmplayer_update_content_type_info(player);
5960 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5963 pad = gst_element_get_static_pad(tf, "src");
5965 LOGE("fail to get typefind src pad.");
5969 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5970 gboolean async = FALSE;
5971 LOGE("failed to autoplug %s", player->type);
5973 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5975 if (async && player->msg_posted == FALSE)
5976 __mmplayer_handle_missed_plugin(player);
5978 gst_object_unref(GST_OBJECT(pad));
5985 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5987 GstElement *decodebin = NULL;
5991 /* create decodebin */
5992 decodebin = gst_element_factory_make("decodebin", NULL);
5995 LOGE("fail to create decodebin");
5999 /* raw pad handling signal */
6000 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6001 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6003 /* no-more-pad pad handling signal */
6004 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6005 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6007 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6008 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6010 /* This signal is emitted when a pad for which there is no further possible
6011 decoding is added to the decodebin.*/
6012 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6013 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6015 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6016 before looking for any elements that can handle that stream.*/
6017 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6018 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6020 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6021 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6022 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6024 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6025 before looking for any elements that can handle that stream.*/
6026 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6027 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6029 /* This signal is emitted once decodebin has finished decoding all the data.*/
6030 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6031 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6033 /* This signal is emitted when a element is added to the bin.*/
6034 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6035 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6042 __mmplayer_gst_make_queue2(mmplayer_t *player)
6044 GstElement *queue2 = NULL;
6045 gint64 dur_bytes = 0L;
6046 mmplayer_gst_element_t *mainbin = NULL;
6047 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6050 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6052 mainbin = player->pipeline->mainbin;
6054 queue2 = gst_element_factory_make("queue2", "queue2");
6056 LOGE("failed to create buffering queue element");
6060 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6061 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6063 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6065 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6066 * skip the pull mode(file or ring buffering) setting. */
6067 if (dur_bytes > 0) {
6068 if (!g_strrstr(player->type, "video/mpegts")) {
6069 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6070 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6076 _mm_player_streaming_set_queue2(player->streamer,
6080 (guint64)dur_bytes); /* no meaning at the moment */
6086 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6088 mmplayer_gst_element_t *mainbin = NULL;
6089 GstElement *decodebin = NULL;
6090 GstElement *queue2 = NULL;
6091 GstPad *sinkpad = NULL;
6092 GstPad *qsrcpad = NULL;
6095 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6097 mainbin = player->pipeline->mainbin;
6099 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6101 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6102 LOGW("need to check: muxed buffer is not null");
6105 queue2 = __mmplayer_gst_make_queue2(player);
6107 LOGE("failed to make queue2");
6111 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6112 LOGE("failed to add buffering queue");
6116 sinkpad = gst_element_get_static_pad(queue2, "sink");
6117 qsrcpad = gst_element_get_static_pad(queue2, "src");
6119 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6120 LOGE("failed to link [%s:%s]-[%s:%s]",
6121 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6125 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6126 LOGE("failed to sync queue2 state with parent");
6130 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6131 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6135 gst_object_unref(GST_OBJECT(sinkpad));
6139 /* create decodebin */
6140 decodebin = _mmplayer_gst_make_decodebin(player);
6142 LOGE("failed to make decodebin");
6146 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6147 LOGE("failed to add decodebin");
6151 /* to force caps on the decodebin element and avoid reparsing stuff by
6152 * typefind. It also avoids a deadlock in the way typefind activates pads in
6153 * the state change */
6154 g_object_set(decodebin, "sink-caps", caps, NULL);
6156 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6158 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6159 LOGE("failed to link [%s:%s]-[%s:%s]",
6160 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6164 gst_object_unref(GST_OBJECT(sinkpad));
6166 gst_object_unref(GST_OBJECT(qsrcpad));
6169 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6170 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6172 /* set decodebin property about buffer in streaming playback. *
6173 * in case of HLS/DASH, it does not need to have big buffer *
6174 * because it is kind of adaptive streaming. */
6175 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6176 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6177 gint high_percent = 0;
6179 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6180 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6182 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6184 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6186 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6187 "high-percent", high_percent,
6188 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6189 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6190 "max-size-buffers", 0, NULL); // disable or automatic
6193 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6194 LOGE("failed to sync decodebin state with parent");
6205 gst_object_unref(GST_OBJECT(sinkpad));
6208 gst_object_unref(GST_OBJECT(qsrcpad));
6211 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6212 * You need to explicitly set elements to the NULL state before
6213 * dropping the final reference, to allow them to clean up.
6215 gst_element_set_state(queue2, GST_STATE_NULL);
6217 /* And, it still has a parent "player".
6218 * You need to let the parent manage the object instead of unreffing the object directly.
6220 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6221 gst_object_unref(queue2);
6226 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6227 * You need to explicitly set elements to the NULL state before
6228 * dropping the final reference, to allow them to clean up.
6230 gst_element_set_state(decodebin, GST_STATE_NULL);
6232 /* And, it still has a parent "player".
6233 * You need to let the parent manage the object instead of unreffing the object directly.
6236 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6237 gst_object_unref(decodebin);
6245 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6250 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6252 LOGD("class : %s, mime : %s", factory_class, mime);
6254 /* add missing plugin */
6255 /* NOTE : msl should check missing plugin for image mime type.
6256 * Some motion jpeg clips can have playable audio track.
6257 * So, msl have to play audio after displaying popup written video format not supported.
6259 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6260 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6261 LOGD("not found demuxer");
6262 player->not_found_demuxer = TRUE;
6263 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6269 if (!g_strrstr(factory_class, "Demuxer")) {
6270 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6271 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6272 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6274 /* check that clip have multi tracks or not */
6275 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6276 LOGD("video plugin is already linked");
6278 LOGW("add VIDEO to missing plugin");
6279 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6280 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6282 } else if (g_str_has_prefix(mime, "audio")) {
6283 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6284 LOGD("audio plugin is already linked");
6286 LOGW("add AUDIO to missing plugin");
6287 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6288 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6296 return MM_ERROR_NONE;
6300 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6302 mmplayer_t *player = (mmplayer_t *)data;
6306 MMPLAYER_RETURN_IF_FAIL(player);
6308 /* remove fakesink. */
6309 if (!_mmplayer_gst_remove_fakesink(player,
6310 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6311 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6312 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6313 * source element are not same. To overcome this situation, this function will called
6314 * several places and several times. Therefore, this is not an error case.
6319 LOGD("[handle: %p] pipeline has completely constructed", player);
6321 if ((player->msg_posted == FALSE) &&
6322 (player->cmd >= MMPLAYER_COMMAND_START))
6323 __mmplayer_handle_missed_plugin(player);
6325 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6329 __mmplayer_check_profile(void)
6332 static int profile_tv = -1;
6334 if (__builtin_expect(profile_tv != -1, 1))
6337 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6338 switch (*profileName) {
6353 __mmplayer_get_next_uri(mmplayer_t *player)
6355 mmplayer_parse_profile_t profile;
6357 guint num_of_list = 0;
6360 num_of_list = g_list_length(player->uri_info.uri_list);
6361 uri_idx = player->uri_info.uri_idx;
6363 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6364 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6365 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6367 LOGW("next uri does not exist");
6371 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6372 LOGE("failed to parse profile");
6376 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6377 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6378 LOGW("uri type is not supported(%d)", profile.uri_type);
6382 LOGD("success to find next uri %d", uri_idx);
6386 if (!uri || uri_idx == num_of_list) {
6387 LOGE("failed to find next uri");
6391 player->uri_info.uri_idx = uri_idx;
6392 if (mm_player_set_attribute((MMHandleType)player, NULL,
6393 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6394 LOGE("failed to set attribute");
6398 SECURE_LOGD("next playback uri: %s", uri);
6403 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6405 #define REPEAT_COUNT_INFINITE -1
6406 #define REPEAT_COUNT_MIN 2
6407 #define ORIGINAL_URI_ONLY 1
6409 MMHandleType attrs = 0;
6413 guint num_of_uri = 0;
6414 int profile_tv = -1;
6418 LOGD("checking for gapless play option");
6420 if (player->build_audio_offload) {
6421 LOGE("offload path is not supportable.");
6425 if (player->pipeline->textbin) {
6426 LOGE("subtitle path is enabled. gapless play is not supported.");
6430 attrs = MMPLAYER_GET_ATTRS(player);
6432 LOGE("fail to get attributes.");
6436 mm_attrs_multiple_get(player->attrs, NULL,
6437 "content_video_found", &video,
6438 "profile_play_count", &count,
6439 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6441 /* gapless playback is not supported in case of video at TV profile. */
6442 profile_tv = __mmplayer_check_profile();
6443 if (profile_tv && video) {
6444 LOGW("not support video gapless playback");
6448 /* check repeat count in case of audio */
6450 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6451 LOGW("gapless is disabled");
6455 num_of_uri = g_list_length(player->uri_info.uri_list);
6457 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6459 if (num_of_uri == ORIGINAL_URI_ONLY) {
6460 /* audio looping path */
6461 if (count >= REPEAT_COUNT_MIN) {
6462 /* decrease play count */
6463 /* we succeeded to rewind. update play count and then wait for next EOS */
6465 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6466 } else if (count != REPEAT_COUNT_INFINITE) {
6467 LOGD("there is no next uri and no repeat");
6470 LOGD("looping cnt %d", count);
6472 /* gapless playback path */
6473 if (!__mmplayer_get_next_uri(player)) {
6474 LOGE("failed to get next uri");
6481 LOGE("unable to play gapless path. EOS will be posted soon");
6486 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6488 mmplayer_track_t *selector = &player->track[type];
6489 mmplayer_gst_element_t *sinkbin = NULL;
6490 main_element_id_e selectorId = MMPLAYER_M_NUM;
6491 main_element_id_e sinkId = MMPLAYER_M_NUM;
6492 GstPad *srcpad = NULL;
6493 GstPad *sinkpad = NULL;
6494 gboolean send_notice = FALSE;
6497 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6499 LOGD("type %d", type);
6502 case MM_PLAYER_TRACK_TYPE_AUDIO:
6503 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6504 sinkId = MMPLAYER_A_BIN;
6505 sinkbin = player->pipeline->audiobin;
6507 case MM_PLAYER_TRACK_TYPE_VIDEO:
6508 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6509 sinkId = MMPLAYER_V_BIN;
6510 sinkbin = player->pipeline->videobin;
6513 case MM_PLAYER_TRACK_TYPE_TEXT:
6514 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6515 sinkId = MMPLAYER_T_BIN;
6516 sinkbin = player->pipeline->textbin;
6519 LOGE("requested type is not supportable");
6524 if (player->pipeline->mainbin[selectorId].gst) {
6527 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6529 if (selector->event_probe_id != 0)
6530 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6531 selector->event_probe_id = 0;
6533 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6534 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6536 if (srcpad && sinkpad) {
6537 /* after getting drained signal there is no data flows, so no need to do pad_block */
6538 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6539 gst_pad_unlink(srcpad, sinkpad);
6541 /* send custom event to sink pad to handle it at video sink */
6543 LOGD("send custom event to sinkpad");
6544 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6545 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6546 gst_pad_send_event(sinkpad, event);
6550 gst_object_unref(sinkpad);
6553 gst_object_unref(srcpad);
6556 LOGD("selector release");
6558 /* release and unref requests pad from the selector */
6559 for (n = 0; n < selector->streams->len; n++) {
6560 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6561 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6564 g_ptr_array_set_size(selector->streams, 0);
6566 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6567 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6569 player->pipeline->mainbin[selectorId].gst = NULL;
6577 __mmplayer_deactivate_old_path(mmplayer_t *player)
6580 MMPLAYER_RETURN_IF_FAIL(player);
6582 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6583 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6584 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6585 LOGE("deactivate selector error");
6589 _mmplayer_track_destroy(player);
6590 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6592 if (player->streamer) {
6593 _mm_player_streaming_initialize(player->streamer, FALSE);
6594 _mm_player_streaming_destroy(player->streamer);
6595 player->streamer = NULL;
6598 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6604 if (!player->msg_posted) {
6605 MMMessageParamType msg = {0,};
6608 msg.code = MM_ERROR_PLAYER_INTERNAL;
6609 LOGE("gapless_uri_play> deactivate error");
6611 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6612 player->msg_posted = TRUE;
6618 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6620 int result = MM_ERROR_NONE;
6621 mmplayer_t *player = (mmplayer_t *)hplayer;
6624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6625 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6627 if (mm_player_set_attribute(hplayer, NULL,
6628 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6629 LOGE("failed to set attribute");
6630 result = MM_ERROR_PLAYER_INTERNAL;
6632 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6633 LOGE("failed to add the original uri in the uri list.");
6641 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6643 mmplayer_t *player = (mmplayer_t *)hplayer;
6644 guint num_of_list = 0;
6648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6649 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6651 if (player->pipeline && player->pipeline->textbin) {
6652 LOGE("subtitle path is enabled.");
6653 return MM_ERROR_PLAYER_INVALID_STATE;
6656 num_of_list = g_list_length(player->uri_info.uri_list);
6658 if (is_first_path) {
6659 if (num_of_list == 0) {
6660 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6661 SECURE_LOGD("add original path : %s", uri);
6663 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6664 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6666 SECURE_LOGD("change original path : %s", uri);
6669 MMHandleType attrs = 0;
6670 attrs = MMPLAYER_GET_ATTRS(player);
6672 if (num_of_list == 0) {
6673 char *original_uri = NULL;
6676 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6678 if (!original_uri) {
6679 LOGE("there is no original uri.");
6680 return MM_ERROR_PLAYER_INVALID_STATE;
6683 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6684 player->uri_info.uri_idx = 0;
6686 SECURE_LOGD("add original path at first : %s", original_uri);
6690 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6691 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6695 return MM_ERROR_NONE;
6699 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6701 mmplayer_t *player = (mmplayer_t *)hplayer;
6702 char *next_uri = NULL;
6703 guint num_of_list = 0;
6706 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6708 num_of_list = g_list_length(player->uri_info.uri_list);
6710 if (num_of_list > 0) {
6711 gint uri_idx = player->uri_info.uri_idx;
6713 if (uri_idx < num_of_list-1)
6718 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6719 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6721 *uri = g_strdup(next_uri);
6725 return MM_ERROR_NONE;
6729 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6730 GstCaps *caps, gpointer data)
6732 mmplayer_t *player = (mmplayer_t *)data;
6733 const gchar *klass = NULL;
6734 const gchar *mime = NULL;
6735 gchar *caps_str = NULL;
6737 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6738 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6739 caps_str = gst_caps_to_string(caps);
6741 LOGW("unknown type of caps : %s from %s",
6742 caps_str, GST_ELEMENT_NAME(elem));
6744 MMPLAYER_FREEIF(caps_str);
6746 /* There is no available codec. */
6747 __mmplayer_check_not_supported_codec(player, klass, mime);
6751 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6752 GstCaps *caps, gpointer data)
6754 mmplayer_t *player = (mmplayer_t *)data;
6755 const char *mime = NULL;
6756 gboolean ret = TRUE;
6758 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6759 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6761 if (g_str_has_prefix(mime, "audio")) {
6762 GstStructure *caps_structure = NULL;
6763 gint samplerate = 0;
6765 gchar *caps_str = NULL;
6767 caps_structure = gst_caps_get_structure(caps, 0);
6768 gst_structure_get_int(caps_structure, "rate", &samplerate);
6769 gst_structure_get_int(caps_structure, "channels", &channels);
6771 if ((channels > 0 && samplerate == 0)) {
6772 LOGD("exclude audio...");
6776 caps_str = gst_caps_to_string(caps);
6777 /* set it directly because not sent by TAG */
6778 if (g_strrstr(caps_str, "mobile-xmf"))
6779 mm_player_set_attribute((MMHandleType)player, NULL,
6780 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6782 MMPLAYER_FREEIF(caps_str);
6783 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6784 LOGD("already video linked");
6787 LOGD("found new stream");
6794 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6796 gboolean ret = FALSE;
6797 GDBusConnection *conn = NULL;
6799 GVariant *result = NULL;
6800 const gchar *dbus_device_type = NULL;
6801 const gchar *dbus_ret = NULL;
6804 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6806 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6811 result = g_dbus_connection_call_sync(conn,
6812 "org.pulseaudio.Server",
6813 "/org/pulseaudio/StreamManager",
6814 "org.pulseaudio.StreamManager",
6815 "GetCurrentMediaRoutingPath",
6816 g_variant_new("(s)", "out"),
6817 G_VARIANT_TYPE("(ss)"),
6818 G_DBUS_CALL_FLAGS_NONE,
6822 if (!result || err) {
6823 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6828 /* device type is listed in stream-map.json at mmfw-sysconf */
6829 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6831 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6832 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6835 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6836 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6837 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6838 LOGD("audio offload is supportable");
6844 LOGD("audio offload is not supportable");
6847 g_variant_unref(result);
6849 g_object_unref(conn);
6854 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6856 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6857 gint64 position = 0;
6859 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6860 player->pipeline && player->pipeline->mainbin);
6862 MMPLAYER_CMD_LOCK(player);
6863 current_state = MMPLAYER_CURRENT_STATE(player);
6865 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6866 LOGW("getting current position failed in paused");
6868 _mmplayer_unrealize((MMHandleType)player);
6869 _mmplayer_realize((MMHandleType)player);
6871 _mmplayer_set_position((MMHandleType)player, position);
6873 /* async not to be blocked in streaming case */
6874 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6876 _mmplayer_pause((MMHandleType)player);
6878 if (current_state == MM_PLAYER_STATE_PLAYING)
6879 _mmplayer_start((MMHandleType)player);
6880 MMPLAYER_CMD_UNLOCK(player);
6882 LOGD("rebuilding audio pipeline is completed.");
6885 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6887 mmplayer_t *player = (mmplayer_t *)user_data;
6888 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6889 gboolean is_supportable = FALSE;
6891 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6892 LOGW("failed to get device type");
6894 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6896 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6897 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6898 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6899 LOGD("ignore this dev connected info");
6903 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6904 if (player->build_audio_offload == is_supportable) {
6905 LOGD("keep current pipeline without re-building");
6909 /* rebuild pipeline */
6910 LOGD("re-build pipeline - offload: %d", is_supportable);
6911 player->build_audio_offload = FALSE;
6912 __mmplayer_rebuild_audio_pipeline(player);
6918 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6920 unsigned int id = 0;
6922 if (player->audio_device_cb_id != 0) {
6923 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6927 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6928 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6929 LOGD("added device connected cb (%u)", id);
6930 player->audio_device_cb_id = id;
6932 LOGW("failed to add device connected cb");
6939 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6941 mmplayer_t *player = (mmplayer_t *)hplayer;
6944 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6945 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6947 *activated = player->build_audio_offload;
6949 LOGD("offload activated : %d", (int)*activated);
6952 return MM_ERROR_NONE;
6956 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6959 this function need to be updated according to the supported media format
6960 @see player->ini.audio_offload_media_format */
6962 if (__mmplayer_is_only_mp3_type(player->type)) {
6963 LOGD("offload supportable media format type");
6971 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6973 gboolean ret = FALSE;
6974 GstElementFactory *factory = NULL;
6977 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6979 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6980 if (!__mmplayer_is_offload_supported_type(player))
6983 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6984 LOGD("there is no audio offload sink");
6988 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6989 LOGW("there is no audio device type to support offload");
6993 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6995 LOGW("there is no installed audio offload sink element");
6998 gst_object_unref(factory);
7000 if (_mmplayer_acquire_hw_resource(player,
7001 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7002 LOGE("failed to acquire audio offload decoder resource");
7006 if (!__mmplayer_add_audio_device_connected_cb(player))
7009 if (!__mmplayer_is_audio_offload_device_type(player))
7012 LOGD("audio offload can be built");
7017 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7023 static GstAutoplugSelectResult
7024 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7026 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7027 int audio_offload = 0;
7029 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7030 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7032 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7033 LOGD("expose audio path to build offload output path");
7034 player->build_audio_offload = TRUE;
7035 /* update codec info */
7036 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7037 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7038 player->audiodec_linked = 1;
7040 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7044 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7045 And need to consider the multi-track audio content.
7046 There is no HW audio decoder in public. */
7048 /* set stream information */
7049 if (!player->audiodec_linked)
7050 _mmplayer_set_audio_attrs(player, caps);
7052 /* update codec info */
7053 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7054 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7055 player->audiodec_linked = 1;
7057 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7059 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7060 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7062 /* mark video decoder for acquire */
7063 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7064 LOGW("video decoder resource is already acquired, skip it.");
7065 ret = GST_AUTOPLUG_SELECT_SKIP;
7069 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7070 LOGE("failed to acquire video decoder resource");
7071 ret = GST_AUTOPLUG_SELECT_SKIP;
7074 player->interrupted_by_resource = FALSE;
7077 /* update codec info */
7078 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7079 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7080 player->videodec_linked = 1;
7088 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7089 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7091 #define DEFAULT_IDX 0xFFFF
7092 #define MIN_FACTORY_NUM 2
7093 mmplayer_t *player = (mmplayer_t *)data;
7094 GValueArray *new_factories = NULL;
7095 GValue val = { 0, };
7096 GstElementFactory *factory = NULL;
7097 const gchar *klass = NULL;
7098 gchar *factory_name = NULL;
7099 guint hw_dec_idx = DEFAULT_IDX;
7100 guint first_sw_dec_idx = DEFAULT_IDX;
7101 guint last_sw_dec_idx = DEFAULT_IDX;
7102 guint new_pos = DEFAULT_IDX;
7103 guint rm_pos = DEFAULT_IDX;
7104 int audio_codec_type;
7105 int video_codec_type;
7106 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7108 if (factories->n_values < MIN_FACTORY_NUM)
7111 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7112 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7115 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7117 for (int i = 0 ; i < factories->n_values ; i++) {
7118 gchar *hw_dec_info = NULL;
7119 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7121 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7123 LOGW("failed to get factory object");
7126 klass = gst_element_factory_get_klass(factory);
7127 factory_name = GST_OBJECT_NAME(factory);
7130 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7132 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7133 if (!player->need_audio_dec_sorting) {
7134 LOGD("sorting is not required");
7137 codec_type = audio_codec_type;
7138 hw_dec_info = player->ini.audiocodec_element_hw;
7139 sw_dec_info = player->ini.audiocodec_element_sw;
7140 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7141 if (!player->need_video_dec_sorting) {
7142 LOGD("sorting is not required");
7145 codec_type = video_codec_type;
7146 hw_dec_info = player->ini.videocodec_element_hw;
7147 sw_dec_info = player->ini.videocodec_element_sw;
7152 if (g_strrstr(factory_name, hw_dec_info)) {
7155 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7156 if (strstr(factory_name, sw_dec_info[j])) {
7157 last_sw_dec_idx = i;
7158 if (first_sw_dec_idx == DEFAULT_IDX) {
7159 first_sw_dec_idx = i;
7164 if (first_sw_dec_idx == DEFAULT_IDX)
7165 LOGW("unknown codec %s", factory_name);
7169 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7172 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7173 if (hw_dec_idx < first_sw_dec_idx)
7175 new_pos = first_sw_dec_idx;
7176 rm_pos = hw_dec_idx + 1;
7177 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7178 if (last_sw_dec_idx < hw_dec_idx)
7180 new_pos = last_sw_dec_idx + 1;
7181 rm_pos = hw_dec_idx;
7186 /* change position - insert H/W decoder according to the new position */
7187 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7189 LOGW("failed to get factory object");
7192 new_factories = g_value_array_copy(factories);
7193 g_value_init (&val, G_TYPE_OBJECT);
7194 g_value_set_object (&val, factory);
7195 g_value_array_insert(new_factories, new_pos, &val);
7196 g_value_unset (&val);
7197 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7199 for (int i = 0 ; i < new_factories->n_values ; i++) {
7200 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7202 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7203 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7205 LOGE("[Re-arranged] failed to get factory object");
7208 return new_factories;
7212 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7213 GstCaps *caps, GstElementFactory *factory, gpointer data)
7215 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7216 mmplayer_t *player = (mmplayer_t *)data;
7218 gchar *factory_name = NULL;
7219 gchar *caps_str = NULL;
7220 const gchar *klass = NULL;
7223 factory_name = GST_OBJECT_NAME(factory);
7224 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7225 caps_str = gst_caps_to_string(caps);
7227 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7229 /* store type string */
7230 if (player->type == NULL) {
7231 player->type = gst_caps_to_string(caps);
7232 __mmplayer_update_content_type_info(player);
7235 /* filtering exclude keyword */
7236 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7237 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7238 LOGW("skipping [%s] by exculde keyword [%s]",
7239 factory_name, player->ini.exclude_element_keyword[idx]);
7241 result = GST_AUTOPLUG_SELECT_SKIP;
7246 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7247 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7248 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7249 factory_name, player->ini.unsupported_codec_keyword[idx]);
7250 result = GST_AUTOPLUG_SELECT_SKIP;
7255 /* exclude webm format */
7256 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7257 * because webm format is not supportable.
7258 * If webm is disabled in "autoplug-continue", there is no state change
7259 * failure or error because the decodebin will expose the pad directly.
7260 * It make MSL invoke _prepare_async_callback.
7261 * So, we need to disable webm format in "autoplug-select" */
7262 if (caps_str && strstr(caps_str, "webm")) {
7263 LOGW("webm is not supported");
7264 result = GST_AUTOPLUG_SELECT_SKIP;
7268 /* check factory class for filtering */
7269 /* NOTE : msl don't need to use image plugins.
7270 * So, those plugins should be skipped for error handling.
7272 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7273 LOGD("skipping [%s] by not required", factory_name);
7274 result = GST_AUTOPLUG_SELECT_SKIP;
7278 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7279 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7280 // TO CHECK : subtitle if needed, add subparse exception.
7281 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7282 result = GST_AUTOPLUG_SELECT_SKIP;
7286 if (g_strrstr(factory_name, "mpegpsdemux")) {
7287 LOGD("skipping PS container - not support");
7288 result = GST_AUTOPLUG_SELECT_SKIP;
7292 if (g_strrstr(factory_name, "mssdemux"))
7293 player->smooth_streaming = TRUE;
7295 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7296 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7299 GstStructure *str = NULL;
7300 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7302 /* don't make video because of not required */
7303 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7304 (!player->set_mode.video_export)) {
7305 LOGD("no need video decoding, expose pad");
7306 result = GST_AUTOPLUG_SELECT_EXPOSE;
7310 /* get w/h for omx state-tune */
7311 /* FIXME: deprecated? */
7312 str = gst_caps_get_structure(caps, 0);
7313 gst_structure_get_int(str, "width", &width);
7316 if (player->v_stream_caps) {
7317 gst_caps_unref(player->v_stream_caps);
7318 player->v_stream_caps = NULL;
7321 player->v_stream_caps = gst_caps_copy(caps);
7322 LOGD("take caps for video state tune");
7323 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7327 if (g_strrstr(klass, "Codec/Decoder")) {
7328 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7329 if (result != GST_AUTOPLUG_SELECT_TRY) {
7330 LOGW("skip add decoder");
7336 MMPLAYER_FREEIF(caps_str);
7342 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7345 //mmplayer_t *player = (mmplayer_t *)data;
7346 GstCaps *caps = NULL;
7348 LOGD("[Decodebin2] pad-removed signal");
7350 caps = gst_pad_query_caps(new_pad, NULL);
7352 LOGW("query caps is NULL");
7356 gchar *caps_str = NULL;
7357 caps_str = gst_caps_to_string(caps);
7359 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7361 MMPLAYER_FREEIF(caps_str);
7362 gst_caps_unref(caps);
7366 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7368 mmplayer_t *player = (mmplayer_t *)data;
7369 GstIterator *iter = NULL;
7370 GValue item = { 0, };
7372 gboolean done = FALSE;
7373 gboolean is_all_drained = TRUE;
7376 MMPLAYER_RETURN_IF_FAIL(player);
7378 LOGD("got drained signal");
7380 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7381 LOGW("Fail to get cmd lock");
7385 if (!__mmplayer_verify_gapless_play_path(player)) {
7386 LOGD("decoding is finished.");
7387 MMPLAYER_CMD_UNLOCK(player);
7391 _mmplayer_set_reconfigure_state(player, TRUE);
7392 MMPLAYER_CMD_UNLOCK(player);
7394 /* check decodebin src pads whether they received EOS or not */
7395 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7398 switch (gst_iterator_next(iter, &item)) {
7399 case GST_ITERATOR_OK:
7400 pad = g_value_get_object(&item);
7401 if (pad && !GST_PAD_IS_EOS(pad)) {
7402 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7403 is_all_drained = FALSE;
7406 g_value_reset(&item);
7408 case GST_ITERATOR_RESYNC:
7409 gst_iterator_resync(iter);
7411 case GST_ITERATOR_ERROR:
7412 case GST_ITERATOR_DONE:
7417 g_value_unset(&item);
7418 gst_iterator_free(iter);
7420 if (!is_all_drained) {
7421 LOGD("Wait util the all pads get EOS.");
7426 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7427 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7429 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7430 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7431 __mmplayer_deactivate_old_path(player);
7437 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7439 mmplayer_t *player = (mmplayer_t *)data;
7440 const gchar *klass = NULL;
7441 gchar *factory_name = NULL;
7443 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7444 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7446 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7448 if (__mmplayer_add_dump_buffer_probe(player, element))
7449 LOGD("add buffer probe");
7451 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7452 gchar *selected = NULL;
7453 selected = g_strdup(GST_ELEMENT_NAME(element));
7454 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7456 /* update codec info */
7457 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7458 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7459 player->audiodec_linked = 1;
7460 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7461 /* update codec info */
7462 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7463 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7464 player->videodec_linked = 1;
7467 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7468 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7469 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7471 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7472 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7474 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7475 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7476 "max-video-width", player->adaptive_info.limit.width,
7477 "max-video-height", player->adaptive_info.limit.height, NULL);
7479 } else if (g_strrstr(klass, "Demuxer")) {
7481 LOGD("plugged element is demuxer. take it");
7483 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7484 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7487 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7488 int surface_type = 0;
7490 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7493 // to support trust-zone only
7494 if (g_strrstr(factory_name, "asfdemux")) {
7495 LOGD("set file-location %s", player->profile.uri);
7496 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7497 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7498 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7499 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7500 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7501 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7502 (__mmplayer_is_only_mp3_type(player->type))) {
7503 LOGD("[mpegaudioparse] set streaming pull mode.");
7504 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7506 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7507 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7510 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7511 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7512 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7514 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7515 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7517 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7518 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7519 (MMPLAYER_IS_DASH_STREAMING(player))) {
7520 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7521 _mm_player_streaming_set_multiqueue(player->streamer, element);
7522 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7531 __mmplayer_release_misc(mmplayer_t *player)
7534 bool cur_mode = player->set_mode.rich_audio;
7537 MMPLAYER_RETURN_IF_FAIL(player);
7539 player->sent_bos = FALSE;
7540 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7542 player->seek_state = MMPLAYER_SEEK_NONE;
7544 player->total_bitrate = 0;
7545 player->total_maximum_bitrate = 0;
7547 player->not_found_demuxer = 0;
7549 player->last_position = 0;
7550 player->duration = 0;
7551 player->http_content_size = 0;
7552 player->not_supported_codec = MISSING_PLUGIN_NONE;
7553 player->can_support_codec = FOUND_PLUGIN_NONE;
7554 player->pending_seek.is_pending = false;
7555 player->pending_seek.pos = 0;
7556 player->msg_posted = FALSE;
7557 player->has_many_types = FALSE;
7558 player->is_subtitle_force_drop = FALSE;
7559 player->play_subtitle = FALSE;
7560 player->adjust_subtitle_pos = 0;
7561 player->has_closed_caption = FALSE;
7562 player->set_mode.video_export = false;
7563 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7564 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7566 player->set_mode.rich_audio = cur_mode;
7568 if (player->audio_device_cb_id > 0 &&
7569 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7570 LOGW("failed to remove audio device_connected_callback");
7571 player->audio_device_cb_id = 0;
7573 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7574 player->bitrate[i] = 0;
7575 player->maximum_bitrate[i] = 0;
7578 /* free memory related to audio effect */
7579 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7581 if (player->adaptive_info.var_list) {
7582 g_list_free_full(player->adaptive_info.var_list, g_free);
7583 player->adaptive_info.var_list = NULL;
7586 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7587 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7588 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7590 /* Reset video360 settings to their defaults in case if the pipeline is to be
7593 player->video360_metadata.is_spherical = -1;
7594 player->is_openal_plugin_used = FALSE;
7596 player->is_content_spherical = FALSE;
7597 player->is_video360_enabled = TRUE;
7598 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7599 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7600 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7601 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7602 player->video360_zoom = 1.0f;
7603 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7604 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7606 player->sound.rg_enable = false;
7608 __mmplayer_initialize_video_roi(player);
7613 __mmplayer_release_misc_post(mmplayer_t *player)
7615 char *original_uri = NULL;
7618 /* player->pipeline is already released before. */
7619 MMPLAYER_RETURN_IF_FAIL(player);
7621 player->video_decoded_cb = NULL;
7622 player->video_decoded_cb_user_param = NULL;
7623 player->video_stream_prerolled = false;
7625 player->audio_decoded_cb = NULL;
7626 player->audio_decoded_cb_user_param = NULL;
7627 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7629 player->audio_stream_changed_cb = NULL;
7630 player->audio_stream_changed_cb_user_param = NULL;
7632 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7634 /* clean found audio decoders */
7635 if (player->audio_decoders) {
7636 GList *a_dec = player->audio_decoders;
7637 for (; a_dec; a_dec = g_list_next(a_dec)) {
7638 gchar *name = a_dec->data;
7639 MMPLAYER_FREEIF(name);
7641 g_list_free(player->audio_decoders);
7642 player->audio_decoders = NULL;
7645 /* clean the uri list except original uri */
7646 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7647 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7649 LOGW("failed to get original uri info");
7651 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7652 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7654 GList *uri_list = player->uri_info.uri_list;
7655 for (; uri_list; uri_list = g_list_next(uri_list)) {
7656 gchar *uri = uri_list->data;
7657 if (original_uri != uri)
7658 MMPLAYER_FREEIF(uri);
7662 /* clear the audio stream buffer list */
7663 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7665 /* clear the video stream bo list */
7666 __mmplayer_video_stream_destroy_bo_list(player);
7667 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7669 if (player->profile.input_mem.buf) {
7670 free(player->profile.input_mem.buf);
7671 player->profile.input_mem.buf = NULL;
7673 player->profile.input_mem.len = 0;
7674 player->profile.input_mem.offset = 0;
7676 player->uri_info.uri_idx = 0;
7681 __mmplayer_check_subtitle(mmplayer_t *player)
7683 MMHandleType attrs = 0;
7684 char *subtitle_uri = NULL;
7688 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7690 /* get subtitle attribute */
7691 attrs = MMPLAYER_GET_ATTRS(player);
7695 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7696 if (!subtitle_uri || !strlen(subtitle_uri))
7699 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7700 player->is_external_subtitle_present = TRUE;
7708 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7710 MMPLAYER_RETURN_IF_FAIL(player);
7712 if (player->eos_timer) {
7713 LOGD("cancel eos timer");
7714 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7715 player->eos_timer = 0;
7722 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7726 MMPLAYER_RETURN_IF_FAIL(player);
7727 MMPLAYER_RETURN_IF_FAIL(sink);
7729 player->sink_elements = g_list_append(player->sink_elements, sink);
7735 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7739 MMPLAYER_RETURN_IF_FAIL(player);
7740 MMPLAYER_RETURN_IF_FAIL(sink);
7742 player->sink_elements = g_list_remove(player->sink_elements, sink);
7748 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7749 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7751 mmplayer_signal_item_t *item = NULL;
7754 MMPLAYER_RETURN_IF_FAIL(player);
7756 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7757 LOGE("invalid signal type [%d]", type);
7761 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7763 LOGE("cannot connect signal [%s]", signal);
7768 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7769 player->signals[type] = g_list_append(player->signals[type], item);
7775 /* NOTE : be careful with calling this api. please refer to below glib comment
7776 * glib comment : Note that there is a bug in GObject that makes this function much
7777 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7778 * will no longer be called, but, the signal handler is not currently disconnected.
7779 * If the instance is itself being freed at the same time than this doesn't matter,
7780 * since the signal will automatically be removed, but if instance persists,
7781 * then the signal handler will leak. You should not remove the signal yourself
7782 * because in a future versions of GObject, the handler will automatically be
7785 * It's possible to work around this problem in a way that will continue to work
7786 * with future versions of GObject by checking that the signal handler is still
7787 * connected before disconnected it:
7789 * if (g_signal_handler_is_connected(instance, id))
7790 * g_signal_handler_disconnect(instance, id);
7793 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7795 GList *sig_list = NULL;
7796 mmplayer_signal_item_t *item = NULL;
7800 MMPLAYER_RETURN_IF_FAIL(player);
7802 LOGD("release signals type : %d", type);
7804 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7805 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7806 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7807 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7808 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7809 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7813 sig_list = player->signals[type];
7815 for (; sig_list; sig_list = sig_list->next) {
7816 item = sig_list->data;
7818 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7819 if (g_signal_handler_is_connected(item->obj, item->sig))
7820 g_signal_handler_disconnect(item->obj, item->sig);
7823 MMPLAYER_FREEIF(item);
7826 g_list_free(player->signals[type]);
7827 player->signals[type] = NULL;
7835 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7837 mmplayer_t *player = 0;
7838 int prev_display_surface_type = 0;
7842 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7844 player = MM_PLAYER_CAST(handle);
7846 /* check video sinkbin is created */
7847 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7848 LOGW("Videosink is already created");
7849 return MM_ERROR_NONE;
7852 LOGD("videosink element is not yet ready");
7854 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7855 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7857 return MM_ERROR_INVALID_ARGUMENT;
7860 /* load previous attributes */
7861 if (player->attrs) {
7862 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7863 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7864 if (prev_display_surface_type == surface_type) {
7865 LOGD("incoming display surface type is same as previous one, do nothing..");
7867 return MM_ERROR_NONE;
7870 LOGE("failed to load attributes");
7872 return MM_ERROR_PLAYER_INTERNAL;
7875 /* videobin is not created yet, so we just set attributes related to display surface */
7876 LOGD("store display attribute for given surface type(%d)", surface_type);
7877 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7878 "display_overlay", wl_surface_id, NULL);
7881 return MM_ERROR_NONE;
7884 /* Note : if silent is true, then subtitle would not be displayed. :*/
7886 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7888 mmplayer_t *player = (mmplayer_t *)hplayer;
7892 /* check player handle */
7893 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7895 player->set_mode.subtitle_off = silent;
7897 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7901 return MM_ERROR_NONE;
7905 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7907 mmplayer_gst_element_t *mainbin = NULL;
7908 mmplayer_gst_element_t *textbin = NULL;
7909 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7910 GstState current_state = GST_STATE_VOID_PENDING;
7911 GstState element_state = GST_STATE_VOID_PENDING;
7912 GstState element_pending_state = GST_STATE_VOID_PENDING;
7914 GstEvent *event = NULL;
7915 int result = MM_ERROR_NONE;
7917 GstClock *curr_clock = NULL;
7918 GstClockTime base_time, start_time, curr_time;
7923 /* check player handle */
7924 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7926 player->pipeline->mainbin &&
7927 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7929 mainbin = player->pipeline->mainbin;
7930 textbin = player->pipeline->textbin;
7932 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7934 // sync clock with current pipeline
7935 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7936 curr_time = gst_clock_get_time(curr_clock);
7938 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7939 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7941 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7942 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7944 if (current_state > GST_STATE_READY) {
7945 // sync state with current pipeline
7946 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7947 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7948 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7950 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7951 if (GST_STATE_CHANGE_FAILURE == ret) {
7952 LOGE("fail to state change.");
7953 result = MM_ERROR_PLAYER_INTERNAL;
7957 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7958 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7961 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7962 gst_object_unref(curr_clock);
7965 // seek to current position
7966 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7967 result = MM_ERROR_PLAYER_INVALID_STATE;
7968 LOGE("gst_element_query_position failed, invalid state");
7972 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7973 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);
7975 _mmplayer_gst_send_event_to_sink(player, event);
7977 result = MM_ERROR_PLAYER_INTERNAL;
7978 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7982 /* sync state with current pipeline */
7983 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7984 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7985 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7987 return MM_ERROR_NONE;
7990 /* release text pipeline resource */
7991 player->textsink_linked = 0;
7993 /* release signal */
7994 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7996 /* release textbin with it's childs */
7997 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7998 MMPLAYER_FREEIF(player->pipeline->textbin);
7999 player->pipeline->textbin = NULL;
8001 /* release subtitle elem */
8002 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8003 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8009 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8011 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8012 GstState current_state = GST_STATE_VOID_PENDING;
8014 MMHandleType attrs = 0;
8015 mmplayer_gst_element_t *mainbin = NULL;
8016 mmplayer_gst_element_t *textbin = NULL;
8018 gchar *subtitle_uri = NULL;
8019 int result = MM_ERROR_NONE;
8020 const gchar *charset = NULL;
8024 /* check player handle */
8025 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8027 player->pipeline->mainbin &&
8028 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8029 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8031 mainbin = player->pipeline->mainbin;
8032 textbin = player->pipeline->textbin;
8034 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8035 if (current_state < GST_STATE_READY) {
8036 result = MM_ERROR_PLAYER_INVALID_STATE;
8037 LOGE("Pipeline is not in proper state");
8041 attrs = MMPLAYER_GET_ATTRS(player);
8043 LOGE("cannot get content attribute");
8044 result = MM_ERROR_PLAYER_INTERNAL;
8048 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8049 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8050 LOGE("subtitle uri is not proper filepath");
8051 result = MM_ERROR_PLAYER_INVALID_URI;
8055 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8056 LOGE("failed to get storage info of subtitle path");
8057 result = MM_ERROR_PLAYER_INVALID_URI;
8061 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8062 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8064 if (!strcmp(filepath, subtitle_uri)) {
8065 LOGD("subtitle path is not changed");
8068 if (mm_player_set_attribute((MMHandleType)player, NULL,
8069 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8070 LOGE("failed to set attribute");
8075 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8076 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8077 player->subtitle_language_list = NULL;
8078 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8080 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8081 if (ret != GST_STATE_CHANGE_SUCCESS) {
8082 LOGE("failed to change state of textbin to READY");
8083 result = MM_ERROR_PLAYER_INTERNAL;
8087 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8088 if (ret != GST_STATE_CHANGE_SUCCESS) {
8089 LOGE("failed to change state of subparse to READY");
8090 result = MM_ERROR_PLAYER_INTERNAL;
8094 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8095 if (ret != GST_STATE_CHANGE_SUCCESS) {
8096 LOGE("failed to change state of filesrc to READY");
8097 result = MM_ERROR_PLAYER_INTERNAL;
8101 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8103 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8105 charset = _mmplayer_get_charset(filepath);
8107 LOGD("detected charset is %s", charset);
8108 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8111 result = _mmplayer_sync_subtitle_pipeline(player);
8118 /* API to switch between external subtitles */
8120 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8122 int result = MM_ERROR_NONE;
8123 mmplayer_t *player = (mmplayer_t *)hplayer;
8128 /* check player handle */
8129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8131 /* filepath can be null in idle state */
8133 /* check file path */
8134 if ((path = strstr(filepath, "file://")))
8135 result = _mmplayer_exist_file_path(path + 7);
8137 result = _mmplayer_exist_file_path(filepath);
8139 if (result != MM_ERROR_NONE) {
8140 LOGE("invalid subtitle path 0x%X", result);
8141 return result; /* file not found or permission denied */
8145 if (!player->pipeline) {
8147 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8148 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8149 LOGE("failed to set attribute");
8150 return MM_ERROR_PLAYER_INTERNAL;
8153 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8154 /* check filepath */
8155 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8157 if (!__mmplayer_check_subtitle(player)) {
8158 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8159 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8160 LOGE("failed to set attribute");
8161 return MM_ERROR_PLAYER_INTERNAL;
8164 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8165 LOGE("fail to create text pipeline");
8166 return MM_ERROR_PLAYER_INTERNAL;
8169 result = _mmplayer_sync_subtitle_pipeline(player);
8171 result = __mmplayer_change_external_subtitle_language(player, filepath);
8174 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8175 player->is_external_subtitle_added_now = TRUE;
8177 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8178 if (!player->subtitle_language_list) {
8179 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8180 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8181 LOGW("subtitle language list is not updated yet");
8183 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8191 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8193 guint active_idx = 0;
8194 GstStream *stream = NULL;
8195 GList *streams = NULL;
8196 GstEvent *ev = NULL;
8197 GstCaps *caps = NULL;
8199 LOGD("Switching Streams... type: %d, index: %d", type, index);
8201 player->track[type].active_track_index = index;
8203 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8204 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8205 if (player->track[i].total_track_num > 0) {
8206 active_idx = player->track[i].active_track_index;
8207 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8208 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8209 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8211 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8212 caps = gst_stream_get_caps(stream);
8214 _mmplayer_set_audio_attrs(player, caps);
8215 gst_caps_unref(caps);
8221 ev = gst_event_new_select_streams(streams);
8222 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8223 g_list_free(streams);
8225 return MM_ERROR_NONE;
8229 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8231 int result = MM_ERROR_NONE;
8232 gchar *change_pad_name = NULL;
8233 GstPad *sinkpad = NULL;
8234 mmplayer_gst_element_t *mainbin = NULL;
8235 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8236 GstCaps *caps = NULL;
8237 gint total_track_num = 0;
8241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8242 MM_ERROR_PLAYER_NOT_INITIALIZED);
8244 LOGD("Change Track(%d) to %d", type, index);
8246 mainbin = player->pipeline->mainbin;
8248 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8249 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8250 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8253 /* Changing Video Track is not supported. */
8254 LOGE("Track Type Error");
8258 if (mainbin[elem_idx].gst == NULL) {
8259 result = MM_ERROR_PLAYER_NO_OP;
8260 LOGD("Req track doesn't exist");
8264 total_track_num = player->track[type].total_track_num;
8265 if (total_track_num <= 0) {
8266 result = MM_ERROR_PLAYER_NO_OP;
8267 LOGD("Language list is not available");
8271 if ((index < 0) || (index >= total_track_num)) {
8272 result = MM_ERROR_INVALID_ARGUMENT;
8273 LOGD("Not a proper index : %d", index);
8277 /*To get the new pad from the selector*/
8278 change_pad_name = g_strdup_printf("sink_%u", index);
8279 if (change_pad_name == NULL) {
8280 result = MM_ERROR_PLAYER_INTERNAL;
8281 LOGD("Pad does not exists");
8285 LOGD("new active pad name: %s", change_pad_name);
8287 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8288 if (sinkpad == NULL) {
8289 LOGD("sinkpad is NULL");
8290 result = MM_ERROR_PLAYER_INTERNAL;
8294 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8295 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8297 caps = gst_pad_get_current_caps(sinkpad);
8298 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8301 gst_object_unref(sinkpad);
8303 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8304 _mmplayer_set_audio_attrs(player, caps);
8307 gst_caps_unref(caps);
8310 MMPLAYER_FREEIF(change_pad_name);
8315 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8317 int result = MM_ERROR_NONE;
8318 mmplayer_t *player = NULL;
8319 mmplayer_gst_element_t *mainbin = NULL;
8321 gint current_active_index = 0;
8323 GstState current_state = GST_STATE_VOID_PENDING;
8328 player = (mmplayer_t *)hplayer;
8329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8331 if (!player->pipeline) {
8332 LOGE("Track %d pre setting -> %d", type, index);
8334 player->track[type].active_track_index = index;
8338 mainbin = player->pipeline->mainbin;
8340 current_active_index = player->track[type].active_track_index;
8342 /*If index is same as running index no need to change the pad*/
8343 if (current_active_index == index)
8346 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8347 result = MM_ERROR_PLAYER_INVALID_STATE;
8351 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8352 if (current_state < GST_STATE_PAUSED) {
8353 result = MM_ERROR_PLAYER_INVALID_STATE;
8354 LOGW("Pipeline not in porper state");
8358 if (MMPLAYER_USE_DECODEBIN(player)) {
8359 result = __mmplayer_change_selector_pad(player, type, index);
8361 result = __mmplayer_switch_stream(player, type, index);
8363 if (result != MM_ERROR_NONE) {
8364 LOGE("failed to change track");
8368 player->track[type].active_track_index = index;
8370 if (MMPLAYER_USE_DECODEBIN(player)) {
8371 GstEvent *event = NULL;
8372 if (current_state == GST_STATE_PLAYING) {
8373 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8374 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8375 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8377 _mmplayer_gst_send_event_to_sink(player, event);
8379 result = MM_ERROR_PLAYER_INTERNAL;
8390 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8392 mmplayer_t *player = (mmplayer_t *)hplayer;
8396 /* check player handle */
8397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8399 *silent = player->set_mode.subtitle_off;
8401 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8405 return MM_ERROR_NONE;
8409 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8412 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8414 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8415 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8419 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8420 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8421 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8422 mmplayer_dump_t *dump_s;
8423 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8424 if (dump_s == NULL) {
8425 LOGE("malloc fail");
8429 dump_s->dump_element_file = NULL;
8430 dump_s->dump_pad = NULL;
8431 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8433 if (dump_s->dump_pad) {
8434 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8435 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]);
8436 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8437 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);
8438 /* add list for removed buffer probe and close FILE */
8439 player->dump_list = g_list_append(player->dump_list, dump_s);
8440 LOGD("%s sink pad added buffer probe for dump", factory_name);
8443 MMPLAYER_FREEIF(dump_s);
8444 LOGE("failed to get %s sink pad added", factory_name);
8451 static GstPadProbeReturn
8452 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8454 FILE *dump_data = (FILE *)u_data;
8456 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8457 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8459 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8461 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8463 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8465 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8467 gst_buffer_unmap(buffer, &probe_info);
8469 return GST_PAD_PROBE_OK;
8473 __mmplayer_release_dump_list(GList *dump_list)
8475 GList *d_list = dump_list;
8480 for (; d_list; d_list = g_list_next(d_list)) {
8481 mmplayer_dump_t *dump_s = d_list->data;
8482 if (dump_s->dump_pad) {
8483 if (dump_s->probe_handle_id)
8484 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8485 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8487 if (dump_s->dump_element_file) {
8488 fclose(dump_s->dump_element_file);
8489 dump_s->dump_element_file = NULL;
8491 MMPLAYER_FREEIF(dump_s);
8493 g_list_free(dump_list);
8498 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8500 mmplayer_t *player = (mmplayer_t *)hplayer;
8504 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8505 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8507 *exist = (bool)player->has_closed_caption;
8511 return MM_ERROR_NONE;
8515 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8520 LOGD("unref internal gst buffer %p", buffer);
8522 gst_buffer_unref((GstBuffer *)buffer);
8529 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8531 mmplayer_t *player = (mmplayer_t *)hplayer;
8535 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8536 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8538 if (MMPLAYER_IS_STREAMING(player))
8539 *timeout = (int)player->ini.live_state_change_timeout;
8541 *timeout = (int)player->ini.localplayback_state_change_timeout;
8543 LOGD("timeout = %d", *timeout);
8546 return MM_ERROR_NONE;
8550 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8554 MMPLAYER_RETURN_IF_FAIL(player);
8556 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8558 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8559 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8560 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8561 player->storage_info[i].id = -1;
8562 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8564 if (path_type != MMPLAYER_PATH_MAX)
8573 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8575 int ret = MM_ERROR_NONE;
8576 mmplayer_t *player = (mmplayer_t *)hplayer;
8577 MMMessageParamType msg_param = {0, };
8580 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 LOGW("state changed storage %d:%d", id, state);
8584 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8585 return MM_ERROR_NONE;
8587 /* FIXME: text path should be handled seperately. */
8588 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8589 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8590 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8591 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8592 LOGW("external storage is removed");
8594 if (player->msg_posted == FALSE) {
8595 memset(&msg_param, 0, sizeof(MMMessageParamType));
8596 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8597 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8598 player->msg_posted = TRUE;
8601 /* unrealize the player */
8602 ret = _mmplayer_unrealize(hplayer);
8603 if (ret != MM_ERROR_NONE)
8604 LOGE("failed to unrealize");
8612 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8614 int ret = MM_ERROR_NONE;
8615 mmplayer_t *player = (mmplayer_t *)hplayer;
8616 int idx = 0, total = 0;
8617 gchar *result = NULL, *tmp = NULL;
8620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8621 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8623 total = *num = g_list_length(player->adaptive_info.var_list);
8625 LOGW("There is no stream variant info.");
8629 result = g_strdup("");
8630 for (idx = 0 ; idx < total ; idx++) {
8631 stream_variant_t *v_data = NULL;
8632 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8635 gchar data[64] = {0};
8636 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8638 tmp = g_strconcat(result, data, NULL);
8642 LOGW("There is no variant data in %d", idx);
8647 *var_info = (char *)result;
8649 LOGD("variant info %d:%s", *num, *var_info);
8655 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8657 int ret = MM_ERROR_NONE;
8658 mmplayer_t *player = (mmplayer_t *)hplayer;
8661 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8663 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8665 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8666 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8667 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8669 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8670 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8671 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8672 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8674 /* FIXME: seek to current position for applying new variant limitation */
8683 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8685 int ret = MM_ERROR_NONE;
8686 mmplayer_t *player = (mmplayer_t *)hplayer;
8689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8690 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8692 *bandwidth = player->adaptive_info.limit.bandwidth;
8693 *width = player->adaptive_info.limit.width;
8694 *height = player->adaptive_info.limit.height;
8696 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8703 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8705 int ret = MM_ERROR_NONE;
8706 mmplayer_t *player = (mmplayer_t *)hplayer;
8709 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8710 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8711 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8713 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8715 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8716 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8717 else /* live case */
8718 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8720 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8727 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8729 #define IDX_FIRST_SW_CODEC 0
8730 mmplayer_t *player = (mmplayer_t *)hplayer;
8731 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8734 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8737 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8738 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8740 switch (stream_type) {
8741 case MM_PLAYER_STREAM_TYPE_AUDIO:
8742 /* to support audio codec selection, codec info have to be added in ini file as below.
8743 audio codec element hw = xxxx
8744 audio codec element sw = avdec
8745 and in case of audio hw codec is supported and selected,
8746 audio filter elements should be applied depending on the hw capabilities.
8748 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8749 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8750 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8751 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8752 LOGE("There is no audio codec info for codec_type %d", codec_type);
8753 return MM_ERROR_PLAYER_NO_OP;
8756 case MM_PLAYER_STREAM_TYPE_VIDEO:
8757 /* to support video codec selection, codec info have to be added in ini file as below.
8758 video codec element hw = omx
8759 video codec element sw = avdec */
8760 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8761 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8762 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8763 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8764 LOGE("There is no video codec info for codec_type %d", codec_type);
8765 return MM_ERROR_PLAYER_NO_OP;
8769 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8770 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8774 LOGD("update %s codec_type to %d", attr_name, codec_type);
8775 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8778 return MM_ERROR_NONE;
8782 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8784 mmplayer_t *player = (mmplayer_t *)hplayer;
8785 GstElement *rg_vol_element = NULL;
8789 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8791 player->sound.rg_enable = enabled;
8793 /* just hold rgvolume enable value if pipeline is not ready */
8794 if (!player->pipeline || !player->pipeline->audiobin) {
8795 LOGD("pipeline is not ready. holding rgvolume enable value");
8796 return MM_ERROR_NONE;
8799 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8801 if (!rg_vol_element) {
8802 LOGD("rgvolume element is not created");
8803 return MM_ERROR_PLAYER_INTERNAL;
8807 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8809 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8813 return MM_ERROR_NONE;
8817 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8819 mmplayer_t *player = (mmplayer_t *)hplayer;
8820 GstElement *rg_vol_element = NULL;
8821 gboolean enable = FALSE;
8825 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8826 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8828 /* just hold enable_rg value if pipeline is not ready */
8829 if (!player->pipeline || !player->pipeline->audiobin) {
8830 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8831 *enabled = player->sound.rg_enable;
8832 return MM_ERROR_NONE;
8835 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8837 if (!rg_vol_element) {
8838 LOGD("rgvolume element is not created");
8839 return MM_ERROR_PLAYER_INTERNAL;
8842 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8843 *enabled = (bool)enable;
8847 return MM_ERROR_NONE;
8851 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8853 mmplayer_t *player = (mmplayer_t *)hplayer;
8854 MMHandleType attrs = 0;
8856 int ret = MM_ERROR_NONE;
8860 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8862 attrs = MMPLAYER_GET_ATTRS(player);
8863 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8865 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8867 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8868 return MM_ERROR_PLAYER_INTERNAL;
8871 player->video_roi.scale_x = scale_x;
8872 player->video_roi.scale_y = scale_y;
8873 player->video_roi.scale_width = scale_width;
8874 player->video_roi.scale_height = scale_height;
8876 /* check video sinkbin is created */
8877 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8878 return MM_ERROR_NONE;
8880 if (!gst_video_overlay_set_video_roi_area(
8881 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8882 scale_x, scale_y, scale_width, scale_height))
8883 ret = MM_ERROR_PLAYER_INTERNAL;
8885 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8886 scale_x, scale_y, scale_width, scale_height);
8894 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8896 mmplayer_t *player = (mmplayer_t *)hplayer;
8897 int ret = MM_ERROR_NONE;
8901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8902 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8904 *scale_x = player->video_roi.scale_x;
8905 *scale_y = player->video_roi.scale_y;
8906 *scale_width = player->video_roi.scale_width;
8907 *scale_height = player->video_roi.scale_height;
8909 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8910 *scale_x, *scale_y, *scale_width, *scale_height);
8916 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8918 mmplayer_t *player = (mmplayer_t *)hplayer;
8922 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8924 player->client_pid = pid;
8926 LOGD("client pid[%d] %p", pid, player);
8930 return MM_ERROR_NONE;
8934 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8936 mmplayer_t *player = (mmplayer_t *)hplayer;
8937 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8938 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8942 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8943 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8946 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8948 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8950 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8951 return MM_ERROR_NONE;
8953 /* in case of audio codec default type is HW */
8955 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8956 if (player->ini.support_audio_effect)
8957 return MM_ERROR_NONE;
8958 elem_id = MMPLAYER_A_FILTER;
8960 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8961 if (player->ini.support_replaygain_control)
8962 return MM_ERROR_NONE;
8963 elem_id = MMPLAYER_A_RGVOL;
8965 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8966 if (player->ini.support_pitch_control)
8967 return MM_ERROR_NONE;
8968 elem_id = MMPLAYER_A_PITCH;
8970 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8971 if (player->ini.support_audio_effect)
8972 return MM_ERROR_NONE;
8974 /* default case handling is not required */
8977 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8978 LOGW("audio control option [%d] is not available", opt);
8981 /* setting pcm exporting option is allowed before READY state */
8982 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8983 return MM_ERROR_PLAYER_INVALID_STATE;
8985 /* check whether the audio filter exist or not after READY state,
8986 because the sw codec could be added during auto-plugging in some cases */
8987 if (!player->pipeline ||
8988 !player->pipeline->audiobin ||
8989 !player->pipeline->audiobin[elem_id].gst) {
8990 LOGW("there is no audio elem [%d]", elem_id);
8995 LOGD("audio control opt %d, available %d", opt, *available);
8999 return MM_ERROR_NONE;
9003 __mmplayer_update_duration_value(mmplayer_t *player)
9005 gboolean ret = FALSE;
9006 gint64 dur_nsec = 0;
9007 LOGD("try to update duration");
9009 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9010 player->duration = dur_nsec;
9011 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9015 if (player->duration < 0) {
9016 LOGW("duration is Non-Initialized !!!");
9017 player->duration = 0;
9020 /* update streaming service type */
9021 player->streaming_type = _mmplayer_get_stream_service_type(player);
9023 /* check duration is OK */
9024 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9025 /* FIXIT : find another way to get duration here. */
9026 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9032 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9034 /* update audio params
9035 NOTE : We need original audio params and it can be only obtained from src pad of audio
9036 decoder. Below code only valid when we are not using 'resampler' just before
9037 'audioconverter'. */
9038 GstCaps *caps_a = NULL;
9040 gint samplerate = 0, channels = 0;
9041 GstStructure *p = NULL;
9042 GstElement *aconv = NULL;
9044 LOGD("try to update audio attrs");
9046 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9048 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9049 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9050 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9051 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9053 LOGE("there is no audio converter");
9057 pad = gst_element_get_static_pad(aconv, "sink");
9060 LOGW("failed to get pad from audio converter");
9064 caps_a = gst_pad_get_current_caps(pad);
9066 LOGW("not ready to get audio caps");
9067 gst_object_unref(pad);
9071 p = gst_caps_get_structure(caps_a, 0);
9073 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9075 gst_structure_get_int(p, "rate", &samplerate);
9076 gst_structure_get_int(p, "channels", &channels);
9078 mm_player_set_attribute((MMHandleType)player, NULL,
9079 "content_audio_samplerate", samplerate,
9080 "content_audio_channels", channels, NULL);
9082 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9084 gst_caps_unref(caps_a);
9085 gst_object_unref(pad);
9091 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9093 LOGD("try to update video attrs");
9095 GstCaps *caps_v = NULL;
9099 GstStructure *p = NULL;
9101 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9102 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9104 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9106 LOGD("no videosink sink pad");
9110 caps_v = gst_pad_get_current_caps(pad);
9111 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9112 if (!caps_v && player->v_stream_caps) {
9113 caps_v = player->v_stream_caps;
9114 gst_caps_ref(caps_v);
9118 LOGD("no negitiated caps from videosink");
9119 gst_object_unref(pad);
9123 p = gst_caps_get_structure(caps_v, 0);
9124 gst_structure_get_int(p, "width", &width);
9125 gst_structure_get_int(p, "height", &height);
9127 mm_player_set_attribute((MMHandleType)player, NULL,
9128 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9130 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9132 SECURE_LOGD("width : %d height : %d", width, height);
9134 gst_caps_unref(caps_v);
9135 gst_object_unref(pad);
9138 mm_player_set_attribute((MMHandleType)player, NULL,
9139 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9140 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9147 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9149 gboolean ret = FALSE;
9150 guint64 data_size = 0;
9154 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9155 if (!player->duration)
9158 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9159 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9160 if (stat(path, &sb) == 0)
9161 data_size = (guint64)sb.st_size;
9163 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9164 data_size = player->http_content_size;
9167 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9170 guint64 bitrate = 0;
9171 guint64 msec_dur = 0;
9173 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9175 bitrate = data_size * 8 * 1000 / msec_dur;
9176 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9177 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9178 mm_player_set_attribute((MMHandleType)player, NULL,
9179 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9182 LOGD("player duration is less than 0");
9186 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9187 if (player->total_bitrate) {
9188 mm_player_set_attribute((MMHandleType)player, NULL,
9189 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9198 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9200 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9201 data->uri_type = uri_type;
9205 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9207 int ret = MM_ERROR_PLAYER_INVALID_URI;
9209 char *buffer = NULL;
9210 char *seperator = strchr(path, ',');
9211 char ext[100] = {0,}, size[100] = {0,};
9214 if ((buffer = strstr(path, "ext="))) {
9215 buffer += strlen("ext=");
9217 if (strlen(buffer)) {
9218 strncpy(ext, buffer, 99);
9220 if ((seperator = strchr(ext, ','))
9221 || (seperator = strchr(ext, ' '))
9222 || (seperator = strchr(ext, '\0'))) {
9223 seperator[0] = '\0';
9228 if ((buffer = strstr(path, "size="))) {
9229 buffer += strlen("size=");
9231 if (strlen(buffer) > 0) {
9232 strncpy(size, buffer, 99);
9234 if ((seperator = strchr(size, ','))
9235 || (seperator = strchr(size, ' '))
9236 || (seperator = strchr(size, '\0'))) {
9237 seperator[0] = '\0';
9240 mem_size = atoi(size);
9245 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9247 if (mem_size && param) {
9248 if (data->input_mem.buf)
9249 free(data->input_mem.buf);
9250 data->input_mem.buf = malloc(mem_size);
9252 if (data->input_mem.buf) {
9253 memcpy(data->input_mem.buf, param, mem_size);
9254 data->input_mem.len = mem_size;
9255 ret = MM_ERROR_NONE;
9257 LOGE("failed to alloc mem %d", mem_size);
9258 ret = MM_ERROR_PLAYER_INTERNAL;
9261 data->input_mem.offset = 0;
9262 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9269 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9271 gchar *location = NULL;
9274 int ret = MM_ERROR_NONE;
9276 if ((path = strstr(uri, "file://"))) {
9277 location = g_filename_from_uri(uri, NULL, &err);
9278 if (!location || (err != NULL)) {
9279 LOGE("Invalid URI '%s' for filesrc: %s", path,
9280 (err != NULL) ? err->message : "unknown error");
9284 MMPLAYER_FREEIF(location);
9286 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9287 return MM_ERROR_PLAYER_INVALID_URI;
9289 LOGD("path from uri: %s", location);
9292 path = (location != NULL) ? (location) : ((char *)uri);
9295 ret = _mmplayer_exist_file_path(path);
9297 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9298 if (ret == MM_ERROR_NONE) {
9299 if (_mmplayer_is_sdp_file(path)) {
9300 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9301 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9302 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9304 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9305 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9307 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9308 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9310 LOGE("invalid uri, could not play..");
9311 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9314 MMPLAYER_FREEIF(location);
9319 static mmplayer_video_decoded_data_info_t *
9320 __mmplayer_create_stream_from_pad(GstPad *pad)
9322 GstCaps *caps = NULL;
9323 GstStructure *structure = NULL;
9324 unsigned int fourcc = 0;
9325 const gchar *string_format = NULL;
9326 mmplayer_video_decoded_data_info_t *stream = NULL;
9328 MMPixelFormatType format;
9331 caps = gst_pad_get_current_caps(pad);
9333 LOGE("Caps is NULL.");
9338 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9340 structure = gst_caps_get_structure(caps, 0);
9341 gst_structure_get_int(structure, "width", &width);
9342 gst_structure_get_int(structure, "height", &height);
9343 string_format = gst_structure_get_string(structure, "format");
9346 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9347 format = _mmplayer_get_pixtype(fourcc);
9348 gst_video_info_from_caps(&info, caps);
9349 gst_caps_unref(caps);
9352 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9353 LOGE("Wrong condition!!");
9357 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9359 LOGE("failed to alloc mem for video data");
9363 stream->width = width;
9364 stream->height = height;
9365 stream->format = format;
9366 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9372 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9374 unsigned int pitch = 0;
9375 unsigned int size = 0;
9377 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9380 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9381 bo = gst_tizen_memory_get_bos(mem, index);
9383 stream->bo[index] = tbm_bo_ref(bo);
9385 LOGE("failed to get bo for index %d", index);
9388 for (index = 0; index < stream->plane_num; index++) {
9389 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9390 stream->stride[index] = pitch;
9392 stream->elevation[index] = size / pitch;
9394 stream->elevation[index] = stream->height;
9399 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9401 if (stream->format == MM_PIXEL_FORMAT_I420) {
9402 int ret = TBM_SURFACE_ERROR_NONE;
9403 tbm_surface_h surface;
9404 tbm_surface_info_s info;
9406 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9408 ret = tbm_surface_get_info(surface, &info);
9409 if (ret != TBM_SURFACE_ERROR_NONE) {
9410 tbm_surface_destroy(surface);
9414 tbm_surface_destroy(surface);
9415 stream->stride[0] = info.planes[0].stride;
9416 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9417 stream->stride[1] = info.planes[1].stride;
9418 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9419 stream->stride[2] = info.planes[2].stride;
9420 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9421 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9422 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9423 stream->stride[0] = stream->width * 4;
9424 stream->elevation[0] = stream->height;
9425 stream->bo_size = stream->stride[0] * stream->height;
9427 LOGE("Not support format %d", stream->format);
9435 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9437 tbm_bo_handle thandle;
9439 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9440 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9441 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9445 unsigned char *src = NULL;
9446 unsigned char *dest = NULL;
9447 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9449 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9451 LOGE("fail to gst_memory_map");
9455 if (!mapinfo.data) {
9456 LOGE("data pointer is wrong");
9460 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9461 if (!stream->bo[0]) {
9462 LOGE("Fail to tbm_bo_alloc!!");
9466 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9468 LOGE("thandle pointer is wrong");
9472 if (stream->format == MM_PIXEL_FORMAT_I420) {
9473 src_stride[0] = GST_ROUND_UP_4(stream->width);
9474 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9475 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9476 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9479 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9480 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9482 for (i = 0; i < 3; i++) {
9483 src = mapinfo.data + src_offset[i];
9484 dest = thandle.ptr + dest_offset[i];
9489 for (j = 0; j < stream->height >> k; j++) {
9490 memcpy(dest, src, stream->width>>k);
9491 src += src_stride[i];
9492 dest += stream->stride[i];
9495 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9496 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9498 LOGE("Not support format %d", stream->format);
9502 tbm_bo_unmap(stream->bo[0]);
9503 gst_memory_unmap(mem, &mapinfo);
9509 tbm_bo_unmap(stream->bo[0]);
9512 gst_memory_unmap(mem, &mapinfo);
9518 __mmplayer_set_pause_state(mmplayer_t *player)
9520 if (player->sent_bos)
9523 /* rtsp case, get content attrs by GstMessage */
9524 if (MMPLAYER_IS_RTSP_STREAMING(player))
9527 /* it's first time to update all content attrs. */
9528 _mmplayer_update_content_attrs(player, ATTR_ALL);
9532 __mmplayer_set_playing_state(mmplayer_t *player)
9534 gchar *audio_codec = NULL;
9536 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9537 /* initialize because auto resume is done well. */
9538 player->resumed_by_rewind = FALSE;
9539 player->playback_rate = 1.0;
9542 if (player->sent_bos)
9545 /* try to get content metadata */
9547 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9548 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9549 * legacy mmfw-player api
9551 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9553 if ((player->cmd == MMPLAYER_COMMAND_START)
9554 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9555 __mmplayer_handle_missed_plugin(player);
9558 /* check audio codec field is set or not
9559 * we can get it from typefinder or codec's caps.
9561 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9563 /* The codec format can't be sent for audio only case like amr, mid etc.
9564 * Because, parser don't make related TAG.
9565 * So, if it's not set yet, fill it with found data.
9568 if (g_strrstr(player->type, "audio/midi"))
9569 audio_codec = "MIDI";
9570 else if (g_strrstr(player->type, "audio/x-amr"))
9571 audio_codec = "AMR";
9572 else if (g_strrstr(player->type, "audio/mpeg")
9573 && !g_strrstr(player->type, "mpegversion=(int)1"))
9574 audio_codec = "AAC";
9576 audio_codec = "unknown";
9578 if (mm_player_set_attribute((MMHandleType)player, NULL,
9579 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9580 LOGE("failed to set attribute");
9582 LOGD("set audio codec type with caps");