4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
94 #define PLAYER_DISPLAY_MODE_DST_ROI 5
96 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
98 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
99 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
100 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
101 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
103 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
104 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
106 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
108 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
109 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
110 #define DEFAULT_PCM_OUT_CHANNEL 2
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
146 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
147 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
148 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
149 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
153 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
154 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
155 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
157 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static void __mmplayer_release_misc(mmplayer_t *player);
159 static void __mmplayer_release_misc_post(mmplayer_t *player);
160 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
161 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
164 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
166 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
167 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
168 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
169 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
171 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
172 static gpointer __mmplayer_gapless_play_thread(gpointer data);
173 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
174 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
175 static void __mmplayer_release_dump_list(GList *dump_list);
176 static int __mmplayer_gst_realize(mmplayer_t *player);
177 static int __mmplayer_gst_unrealize(mmplayer_t *player);
178 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
179 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
182 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
183 static void __mmplayer_check_pipeline(mmplayer_t *player);
184 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
185 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
186 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
187 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
188 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
189 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
190 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
191 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
192 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
193 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
194 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
195 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
197 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
198 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
199 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
201 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
202 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
203 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
204 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
206 static void __mmplayer_set_pause_state(mmplayer_t *player);
207 static void __mmplayer_set_playing_state(mmplayer_t *player);
208 /*===========================================================================================
210 | FUNCTION DEFINITIONS |
212 ========================================================================================== */
216 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
220 count = gst_tag_list_get_tag_size(list, tag);
222 LOGD("count = %d", count);
224 for (i = 0; i < count; i++) {
227 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
228 if (!gst_tag_list_get_string_index(list, tag, i, &str))
229 g_assert_not_reached();
231 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
235 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
237 g_print(" : %s", str);
244 /* This function should be called after the pipeline goes PAUSED or higher
247 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
249 static gboolean has_duration = FALSE;
250 static gboolean has_video_attrs = FALSE;
251 static gboolean has_audio_attrs = FALSE;
252 static gboolean has_bitrate = FALSE;
253 gboolean missing_only = FALSE;
254 gboolean all = FALSE;
255 MMHandleType attrs = 0;
259 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
261 /* check player state here */
262 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
263 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
264 /* give warning now only */
265 LOGW("be careful. content attributes may not available in this state ");
268 /* get content attribute first */
269 attrs = MMPLAYER_GET_ATTRS(player);
271 LOGE("cannot get content attribute");
275 /* get update flag */
277 if (flag & ATTR_MISSING_ONLY) {
279 LOGD("updating missed attr only");
282 if (flag & ATTR_ALL) {
284 has_duration = FALSE;
285 has_video_attrs = FALSE;
286 has_audio_attrs = FALSE;
289 LOGD("updating all attrs");
292 if (missing_only && all) {
293 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
294 missing_only = FALSE;
297 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
298 has_duration = __mmplayer_update_duration_value(player);
300 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
301 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
303 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
304 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
306 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
307 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
310 if (mm_attrs_commit_all(attrs)) {
311 LOGE("failed to update attributes");
321 _mmplayer_get_stream_service_type(mmplayer_t *player)
323 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
327 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
329 player->pipeline->mainbin &&
330 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
331 STREAMING_SERVICE_NONE);
333 /* streaming service type if streaming */
334 if (!MMPLAYER_IS_STREAMING(player))
335 return STREAMING_SERVICE_NONE;
337 streaming_type = (player->duration == 0) ?
338 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
340 switch (streaming_type) {
341 case STREAMING_SERVICE_LIVE:
342 LOGD("it's live streaming");
344 case STREAMING_SERVICE_VOD:
345 LOGD("it's vod streaming");
348 LOGE("should not get here");
354 return streaming_type;
357 /* this function sets the player state and also report
358 * it to applicaton by calling callback function
361 _mmplayer_set_state(mmplayer_t *player, int state)
363 MMMessageParamType msg = {0, };
365 MMPLAYER_RETURN_IF_FAIL(player);
367 if (MMPLAYER_CURRENT_STATE(player) == state) {
368 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
369 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
373 /* update player states */
374 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
375 MMPLAYER_CURRENT_STATE(player) = state;
377 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
378 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
381 MMPLAYER_PRINT_STATE(player);
383 switch (MMPLAYER_CURRENT_STATE(player)) {
384 case MM_PLAYER_STATE_NULL:
385 case MM_PLAYER_STATE_READY:
387 case MM_PLAYER_STATE_PAUSED:
388 __mmplayer_set_pause_state(player);
390 case MM_PLAYER_STATE_PLAYING:
391 __mmplayer_set_playing_state(player);
393 case MM_PLAYER_STATE_NONE:
395 LOGW("invalid target state, there is nothing to do.");
400 /* post message to application */
401 if (MMPLAYER_TARGET_STATE(player) == state) {
402 /* fill the message with state of player */
403 msg.union_type = MM_MSG_UNION_STATE;
404 msg.state.previous = MMPLAYER_PREV_STATE(player);
405 msg.state.current = MMPLAYER_CURRENT_STATE(player);
407 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
409 /* state changed by resource callback */
410 if (player->interrupted_by_resource)
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
412 else /* state changed by usecase */
413 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
416 LOGD("intermediate state, do nothing.");
417 MMPLAYER_PRINT_STATE(player);
421 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
422 && !player->sent_bos) {
423 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
424 player->sent_bos = TRUE;
431 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
433 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
434 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
438 //LOGD("incomming command : %d ", command);
440 current_state = MMPLAYER_CURRENT_STATE(player);
441 pending_state = MMPLAYER_PENDING_STATE(player);
443 MMPLAYER_PRINT_STATE(player);
446 case MMPLAYER_COMMAND_CREATE:
448 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
450 if (current_state == MM_PLAYER_STATE_NULL ||
451 current_state == MM_PLAYER_STATE_READY ||
452 current_state == MM_PLAYER_STATE_PAUSED ||
453 current_state == MM_PLAYER_STATE_PLAYING)
458 case MMPLAYER_COMMAND_DESTROY:
460 /* destroy can called anytime */
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
466 case MMPLAYER_COMMAND_REALIZE:
468 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
470 if (pending_state != MM_PLAYER_STATE_NONE) {
473 /* need ready state to realize */
474 if (current_state == MM_PLAYER_STATE_READY)
477 if (current_state != MM_PLAYER_STATE_NULL)
483 case MMPLAYER_COMMAND_UNREALIZE:
485 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
487 if (current_state == MM_PLAYER_STATE_NULL)
492 case MMPLAYER_COMMAND_START:
494 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
496 if (pending_state == MM_PLAYER_STATE_NONE) {
497 if (current_state == MM_PLAYER_STATE_PLAYING)
499 else if (current_state != MM_PLAYER_STATE_READY &&
500 current_state != MM_PLAYER_STATE_PAUSED)
502 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
504 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
505 LOGD("player is going to paused state, just change the pending state as playing");
512 case MMPLAYER_COMMAND_STOP:
514 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
516 if (current_state == MM_PLAYER_STATE_READY)
519 /* need playing/paused state to stop */
520 if (current_state != MM_PLAYER_STATE_PLAYING &&
521 current_state != MM_PLAYER_STATE_PAUSED)
526 case MMPLAYER_COMMAND_PAUSE:
528 if (MMPLAYER_IS_LIVE_STREAMING(player))
531 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
532 goto NOT_COMPLETED_SEEK;
534 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
536 if (pending_state == MM_PLAYER_STATE_NONE) {
537 if (current_state == MM_PLAYER_STATE_PAUSED)
539 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
541 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
543 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
544 if (current_state == MM_PLAYER_STATE_PAUSED)
545 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
552 case MMPLAYER_COMMAND_RESUME:
554 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
555 goto NOT_COMPLETED_SEEK;
557 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
559 if (pending_state == MM_PLAYER_STATE_NONE) {
560 if (current_state == MM_PLAYER_STATE_PLAYING)
562 else if (current_state != MM_PLAYER_STATE_PAUSED)
564 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
566 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
567 LOGD("player is going to paused state, just change the pending state as playing");
577 player->cmd = command;
579 return MM_ERROR_NONE;
582 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
583 MMPLAYER_STATE_GET_NAME(current_state), command);
584 return MM_ERROR_PLAYER_INVALID_STATE;
587 LOGW("not completed seek");
588 return MM_ERROR_PLAYER_DOING_SEEK;
591 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
592 return MM_ERROR_PLAYER_NO_OP;
595 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
596 return MM_ERROR_PLAYER_NO_OP;
600 __mmplayer_initialize_gapless_play(mmplayer_t *player)
603 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
607 player->smooth_streaming = FALSE;
608 player->videodec_linked = 0;
609 player->audiodec_linked = 0;
610 player->textsink_linked = 0;
611 player->is_external_subtitle_present = FALSE;
612 player->is_external_subtitle_added_now = FALSE;
613 player->not_supported_codec = MISSING_PLUGIN_NONE;
614 player->can_support_codec = FOUND_PLUGIN_NONE;
615 player->pending_seek.is_pending = false;
616 player->pending_seek.pos = 0;
617 player->msg_posted = FALSE;
618 player->has_many_types = FALSE;
619 player->no_more_pad = FALSE;
620 player->not_found_demuxer = 0;
621 player->seek_state = MMPLAYER_SEEK_NONE;
622 player->is_subtitle_force_drop = FALSE;
623 player->play_subtitle = FALSE;
624 player->adjust_subtitle_pos = 0;
626 player->total_bitrate = 0;
627 player->total_maximum_bitrate = 0;
629 _mmplayer_track_initialize(player);
630 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
632 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
633 player->bitrate[i] = 0;
634 player->maximum_bitrate[i] = 0;
637 if (player->v_stream_caps) {
638 gst_caps_unref(player->v_stream_caps);
639 player->v_stream_caps = NULL;
642 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
644 /* clean found audio decoders */
645 if (player->audio_decoders) {
646 GList *a_dec = player->audio_decoders;
647 for (; a_dec; a_dec = g_list_next(a_dec)) {
648 gchar *name = a_dec->data;
649 MMPLAYER_FREEIF(name);
651 g_list_free(player->audio_decoders);
652 player->audio_decoders = NULL;
655 /* release video decoder resource */
656 if (player->video_decoder_resource != NULL) {
657 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager,
658 player->video_decoder_resource);
659 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
660 LOGE("failed to mark the video decoder resource for release, ret(0x%x)", rm_ret);
663 player->video_decoder_resource = NULL;
666 rm_ret = mm_resource_manager_commit(player->resource_manager);
667 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
668 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
676 __mmplayer_gapless_play_thread(gpointer data)
678 mmplayer_t *player = (mmplayer_t *)data;
679 mmplayer_gst_element_t *mainbin = NULL;
681 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
683 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
684 while (!player->gapless_play_thread_exit) {
685 LOGD("gapless play thread started. waiting for signal.");
686 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
688 LOGD("reconfigure pipeline for gapless play.");
690 if (player->gapless_play_thread_exit) {
691 if (player->gapless.reconfigure) {
692 player->gapless.reconfigure = false;
693 MMPLAYER_PLAYBACK_UNLOCK(player);
695 LOGD("exiting gapless play thread");
699 mainbin = player->pipeline->mainbin;
701 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
702 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
703 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
704 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
705 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
707 /* Initialize Player values */
708 __mmplayer_initialize_gapless_play(player);
710 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
712 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
718 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
720 GSource *source = NULL;
724 source = g_main_context_find_source_by_id(context, source_id);
725 if (source != NULL) {
726 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
727 g_source_destroy(source);
734 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
736 mmplayer_t *player = (mmplayer_t *)hplayer;
737 GstMessage *msg = NULL;
738 GQueue *queue = NULL;
741 MMPLAYER_RETURN_IF_FAIL(player);
743 /* disconnecting bus watch */
744 if (player->bus_watcher)
745 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
746 player->bus_watcher = 0;
748 /* destroy the gst bus msg thread */
749 if (player->bus_msg_thread) {
750 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
751 player->bus_msg_thread_exit = TRUE;
752 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
753 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
755 LOGD("gst bus msg thread exit.");
756 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
757 player->bus_msg_thread = NULL;
759 g_mutex_clear(&player->bus_msg_thread_mutex);
760 g_cond_clear(&player->bus_msg_thread_cond);
763 g_mutex_lock(&player->bus_msg_q_lock);
764 queue = player->bus_msg_q;
765 while (!g_queue_is_empty(queue)) {
766 msg = (GstMessage *)g_queue_pop_head(queue);
771 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
772 gst_message_unref(msg);
774 g_mutex_unlock(&player->bus_msg_q_lock);
780 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
782 GstElement *parent = NULL;
784 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
785 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
788 MMPLAYER_FSINK_LOCK(player);
790 /* get parent of fakesink */
791 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
793 LOGD("fakesink already removed");
797 gst_element_set_locked_state(fakesink->gst, TRUE);
799 /* setting the state to NULL never returns async
800 * so no need to wait for completion of state transiton
802 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
803 LOGE("fakesink state change failure!");
804 /* FIXIT : should I return here? or try to proceed to next? */
807 /* remove fakesink from it's parent */
808 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
809 LOGE("failed to remove fakesink");
811 gst_object_unref(parent);
816 gst_object_unref(parent);
818 LOGD("state-holder removed");
820 gst_element_set_locked_state(fakesink->gst, FALSE);
822 MMPLAYER_FSINK_UNLOCK(player);
827 gst_element_set_locked_state(fakesink->gst, FALSE);
829 MMPLAYER_FSINK_UNLOCK(player);
833 static GstPadProbeReturn
834 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
836 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
837 return GST_PAD_PROBE_OK;
841 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
843 gint64 stop_running_time = 0;
844 gint64 position_running_time = 0;
848 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
849 if ((player->gapless.update_segment[idx] == TRUE) ||
850 !(player->selector[idx].event_probe_id)) {
851 /* LOGW("[%d] skip", idx); */
855 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
857 gst_segment_to_running_time(&player->gapless.segment[idx],
858 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
859 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
861 gst_segment_to_running_time(&player->gapless.segment[idx],
862 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
864 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
866 gst_segment_to_running_time(&player->gapless.segment[idx],
867 GST_FORMAT_TIME, player->duration);
870 position_running_time =
871 gst_segment_to_running_time(&player->gapless.segment[idx],
872 GST_FORMAT_TIME, player->gapless.segment[idx].position);
874 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
875 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
877 GST_TIME_ARGS(stop_running_time),
878 GST_TIME_ARGS(position_running_time),
879 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
880 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
882 position_running_time = MAX(position_running_time, stop_running_time);
883 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
884 GST_FORMAT_TIME, player->gapless.segment[idx].start);
885 position_running_time = MAX(0, position_running_time);
886 position = MAX(position, position_running_time);
890 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
891 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
892 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
894 player->gapless.start_time[stream_type] += position;
900 static GstPadProbeReturn
901 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
903 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
904 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
905 mmplayer_t *player = (mmplayer_t *)data;
906 GstCaps *caps = NULL;
907 GstStructure *str = NULL;
908 const gchar *name = NULL;
909 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
910 gboolean caps_ret = TRUE;
912 if (GST_EVENT_IS_DOWNSTREAM(event) &&
913 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
914 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
915 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
916 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
918 } else if (GST_EVENT_IS_UPSTREAM(event) &&
919 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
923 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
927 if (strstr(name, "audio")) {
928 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
929 } else if (strstr(name, "video")) {
930 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
932 /* text track is not supportable */
933 LOGE("invalid name %s", name);
937 switch (GST_EVENT_TYPE(event)) {
940 /* in case of gapless, drop eos event not to send it to sink */
941 if (player->gapless.reconfigure && !player->msg_posted) {
942 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
943 ret = GST_PAD_PROBE_DROP;
947 case GST_EVENT_STREAM_START:
949 __mmplayer_gst_selector_update_start_time(player, stream_type);
952 case GST_EVENT_FLUSH_STOP:
954 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
955 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
956 player->gapless.start_time[stream_type] = 0;
959 case GST_EVENT_SEGMENT:
964 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
965 gst_event_copy_segment(event, &segment);
967 if (segment.format != GST_FORMAT_TIME)
970 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
971 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
972 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
973 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
974 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
975 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
977 /* keep the all the segment ev to cover the seeking */
978 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
979 player->gapless.update_segment[stream_type] = TRUE;
981 if (!player->gapless.running)
984 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
986 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
988 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
989 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
990 gst_event_unref(event);
991 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
997 gdouble proportion = 0.0;
998 GstClockTimeDiff diff = 0;
999 GstClockTime timestamp = 0;
1000 gint64 running_time_diff = -1;
1001 GstQOSType type = 0;
1002 GstEvent *tmpev = NULL;
1004 running_time_diff = player->gapless.segment[stream_type].base;
1006 if (running_time_diff <= 0) /* don't need to adjust */
1009 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1010 gst_event_unref(event);
1012 if (timestamp < running_time_diff) {
1013 LOGW("QOS event from previous group");
1014 ret = GST_PAD_PROBE_DROP;
1018 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1019 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1020 stream_type, GST_TIME_ARGS(timestamp),
1021 GST_TIME_ARGS(running_time_diff),
1022 GST_TIME_ARGS(timestamp - running_time_diff));
1024 timestamp -= running_time_diff;
1026 /* That case is invalid for QoS events */
1027 if (diff < 0 && -diff > timestamp) {
1028 LOGW("QOS event from previous group");
1029 ret = GST_PAD_PROBE_DROP;
1033 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1034 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1044 gst_caps_unref(caps);
1048 /* create fakesink for audio or video path witout audiobin or videobin */
1050 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1052 GstElement *pipeline = NULL;
1053 GstElement *fakesink = NULL;
1054 GstPad *sinkpad = NULL;
1057 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1062 fakesink = gst_element_factory_make("fakesink", NULL);
1063 if (fakesink == NULL) {
1064 LOGE("failed to create fakesink");
1068 /* store it as it's sink element */
1069 __mmplayer_add_sink(player, fakesink);
1071 gst_bin_add(GST_BIN(pipeline), fakesink);
1074 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1076 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1078 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1079 LOGE("failed to link fakesink");
1080 gst_object_unref(GST_OBJECT(fakesink));
1084 if (strstr(name, "video")) {
1085 if (player->v_stream_caps) {
1086 gst_caps_unref(player->v_stream_caps);
1087 player->v_stream_caps = NULL;
1089 if (player->ini.set_dump_element_flag)
1090 __mmplayer_add_dump_buffer_probe(player, fakesink);
1093 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1094 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1098 gst_object_unref(GST_OBJECT(sinkpad));
1105 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1107 GstElement *pipeline = NULL;
1108 GstElement *selector = NULL;
1109 GstPad *srcpad = NULL;
1112 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1114 selector = gst_element_factory_make("input-selector", NULL);
1116 LOGE("failed to create input-selector");
1119 g_object_set(selector, "sync-streams", TRUE, NULL);
1121 player->pipeline->mainbin[elem_idx].id = elem_idx;
1122 player->pipeline->mainbin[elem_idx].gst = selector;
1124 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1126 srcpad = gst_element_get_static_pad(selector, "src");
1128 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1129 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1130 __mmplayer_gst_selector_blocked, NULL, NULL);
1131 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1132 __mmplayer_gst_selector_event_probe, player, NULL);
1134 gst_element_set_state(selector, GST_STATE_PAUSED);
1136 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1137 gst_bin_add(GST_BIN(pipeline), selector);
1139 gst_object_unref(GST_OBJECT(srcpad));
1146 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1148 mmplayer_t *player = (mmplayer_t *)data;
1149 GstElement *selector = NULL;
1150 GstCaps *caps = NULL;
1151 GstStructure *str = NULL;
1152 const gchar *name = NULL;
1153 GstPad *sinkpad = NULL;
1154 gboolean first_track = FALSE;
1155 gboolean caps_ret = TRUE;
1157 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1158 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1161 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1162 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1164 LOGD("pad-added signal handling");
1166 /* get mimetype from caps */
1167 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1171 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1172 /* LOGD("detected mimetype : %s", name); */
1174 if (strstr(name, "video")) {
1176 gchar *caps_str = NULL;
1178 caps_str = gst_caps_to_string(caps);
1179 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1180 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1181 player->set_mode.video_zc = true;
1183 MMPLAYER_FREEIF(caps_str);
1185 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1186 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1188 LOGD("surface type : %d", stype);
1190 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1191 __mmplayer_gst_create_sinkbin(elem, pad, player);
1195 /* in case of exporting video frame, it requires the 360 video filter.
1196 * it will be handled in _no_more_pads(). */
1197 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1198 __mmplayer_gst_make_fakesink(player, pad, name);
1202 LOGD("video selector is required");
1203 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1204 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1205 } else if (strstr(name, "audio")) {
1206 gint samplerate = 0;
1209 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1210 if (player->build_audio_offload)
1211 player->no_more_pad = TRUE; /* remove state holder */
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 gst_structure_get_int(str, "rate", &samplerate);
1217 gst_structure_get_int(str, "channels", &channels);
1219 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1220 __mmplayer_gst_make_fakesink(player, pad, name);
1224 LOGD("audio selector is required");
1225 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1226 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1228 } else if (strstr(name, "text")) {
1229 LOGD("text selector is required");
1230 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1233 LOGE("invalid caps info");
1237 /* check selector and create it */
1238 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1239 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1244 LOGD("input-selector is already created.");
1248 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1250 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1252 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1253 LOGE("failed to link selector");
1254 gst_object_unref(GST_OBJECT(selector));
1259 LOGD("this track will be activated");
1260 g_object_set(selector, "active-pad", sinkpad, NULL);
1263 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1269 gst_caps_unref(caps);
1272 gst_object_unref(GST_OBJECT(sinkpad));
1280 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1282 GstPad *srcpad = NULL;
1285 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1287 LOGD("type %d", type);
1290 LOGD("there is no %d track", type);
1294 srcpad = gst_element_get_static_pad(selector, "src");
1296 LOGE("failed to get srcpad from selector");
1300 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1302 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1304 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1305 if (player->selector[type].block_id) {
1306 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1307 player->selector[type].block_id = 0;
1311 gst_object_unref(GST_OBJECT(srcpad));
1320 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1322 MMHandleType attrs = 0;
1323 gint active_index = 0;
1326 MMPLAYER_RETURN_IF_FAIL(player);
1328 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1330 /* change track to active pad */
1331 active_index = player->selector[type].active_pad_index;
1332 if ((active_index != DEFAULT_TRACK) &&
1333 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1334 LOGW("failed to change %d type track to %d", type, active_index);
1335 player->selector[type].active_pad_index = DEFAULT_TRACK;
1339 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1340 attrs = MMPLAYER_GET_ATTRS(player);
1342 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1343 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1345 if (mm_attrs_commit_all(attrs))
1346 LOGW("failed to commit attrs.");
1348 LOGW("cannot get content attribute");
1357 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1360 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1362 if (!audio_selector) {
1363 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1365 /* in case the source is changed, output can be changed. */
1366 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1367 LOGD("remove previous audiobin if it exist");
1369 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1370 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1372 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1373 MMPLAYER_FREEIF(player->pipeline->audiobin);
1376 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1377 __mmplayer_pipeline_complete(NULL, player);
1382 /* apply the audio track information */
1383 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1385 /* create audio sink path */
1386 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1387 LOGE("failed to create audio sink path");
1396 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1399 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1401 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1402 LOGD("text path is not supproted");
1406 /* apply the text track information */
1407 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1409 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1410 player->has_closed_caption = TRUE;
1412 /* create text decode path */
1413 player->no_more_pad = TRUE;
1415 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1416 LOGE("failed to create text sink path");
1425 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1427 gint64 dur_bytes = 0L;
1430 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1431 player->pipeline->mainbin && player->streamer, FALSE);
1433 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1434 LOGE("fail to get duration.");
1436 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1437 * use file information was already set on Q2 when it was created. */
1438 _mm_player_streaming_set_queue2(player->streamer,
1439 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1440 TRUE, /* use_buffering */
1441 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1442 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1449 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1451 mmplayer_t *player = NULL;
1452 GstElement *video_selector = NULL;
1453 GstElement *audio_selector = NULL;
1454 GstElement *text_selector = NULL;
1457 player = (mmplayer_t *)data;
1459 LOGD("no-more-pad signal handling");
1461 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1462 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1463 LOGW("player is shutting down");
1467 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1468 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1469 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1470 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1471 LOGE("failed to set queue2 buffering");
1476 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1477 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1478 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1480 if (!video_selector && !audio_selector && !text_selector) {
1481 LOGW("there is no selector");
1482 player->no_more_pad = TRUE;
1486 /* create video path followed by video-select */
1487 if (video_selector && !audio_selector && !text_selector)
1488 player->no_more_pad = TRUE;
1490 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1493 /* create audio path followed by audio-select */
1494 if (audio_selector && !text_selector)
1495 player->no_more_pad = TRUE;
1497 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1500 /* create text path followed by text-select */
1501 __mmplayer_create_text_sink_path(player, text_selector);
1504 if (player->gapless.reconfigure) {
1505 player->gapless.reconfigure = FALSE;
1506 MMPLAYER_PLAYBACK_UNLOCK(player);
1513 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1515 gboolean ret = FALSE;
1516 GstElement *pipeline = NULL;
1517 GstPad *sinkpad = NULL;
1520 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1521 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1523 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1525 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1527 LOGE("failed to get pad from sinkbin");
1533 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1534 LOGE("failed to link sinkbin for reusing");
1535 goto EXIT; /* exit either pass or fail */
1539 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1540 LOGE("failed to set state(READY) to sinkbin");
1545 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1546 LOGE("failed to add sinkbin to pipeline");
1551 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1552 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1557 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1558 LOGE("failed to set state(PAUSED) to sinkbin");
1567 gst_object_unref(GST_OBJECT(sinkpad));
1575 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1577 mmplayer_t *player = NULL;
1578 GstCaps *caps = NULL;
1579 gchar *caps_str = NULL;
1580 GstStructure *str = NULL;
1581 const gchar *name = NULL;
1582 GstElement *sinkbin = NULL;
1583 gboolean reusing = FALSE;
1584 gboolean caps_ret = TRUE;
1585 gchar *sink_pad_name = "sink";
1588 player = (mmplayer_t *)data;
1591 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1592 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1594 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1598 caps_str = gst_caps_to_string(caps);
1600 /* LOGD("detected mimetype : %s", name); */
1601 if (strstr(name, "audio")) {
1602 if (player->pipeline->audiobin == NULL) {
1603 const gchar *audio_format = gst_structure_get_string(str, "format");
1605 LOGD("original audio format %s", audio_format);
1606 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1609 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1610 LOGE("failed to create audiobin. continuing without audio");
1614 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1615 LOGD("creating audiobin success");
1618 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1619 LOGD("reusing audiobin");
1620 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1622 } else if (strstr(name, "video")) {
1623 /* 1. zero copy is updated at _decode_pad_added()
1624 * 2. NULL surface type is handled in _decode_pad_added() */
1625 LOGD("zero copy %d", player->set_mode.video_zc);
1626 if (player->pipeline->videobin == NULL) {
1627 int surface_type = 0;
1628 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1629 LOGD("display_surface_type (%d)", surface_type);
1631 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1632 LOGD("mark video overlay for acquire");
1633 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1634 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1635 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1636 &player->video_overlay_resource)
1637 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1638 LOGE("could not mark video_overlay resource for acquire");
1643 player->interrupted_by_resource = FALSE;
1645 if (mm_resource_manager_commit(player->resource_manager) !=
1646 MM_RESOURCE_MANAGER_ERROR_NONE) {
1647 LOGE("could not acquire resources for video playing");
1651 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1652 LOGE("failed to create videobin. continuing without video");
1656 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1657 LOGD("creating videosink bin success");
1660 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1661 LOGD("re-using videobin");
1662 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1664 } else if (strstr(name, "text")) {
1665 if (player->pipeline->textbin == NULL) {
1666 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1667 LOGE("failed to create text sink bin. continuing without text");
1671 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1672 player->textsink_linked = 1;
1673 LOGD("creating textsink bin success");
1675 if (!player->textsink_linked) {
1676 LOGD("re-using textbin");
1678 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1679 player->textsink_linked = 1;
1681 /* linked textbin exist which means that the external subtitle path exist already */
1682 LOGW("ignoring internal subtutle since external subtitle is available");
1685 sink_pad_name = "text_sink";
1687 LOGW("unknown mime type %s, ignoring it", name);
1691 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1694 LOGD("[handle: %p] success to create and link sink bin", player);
1696 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1697 * streaming task. if the task blocked, then buffer will not flow to the next element
1698 *(autoplugging element). so this is special hack for streaming. please try to remove it
1700 /* dec stream count. we can remove fakesink if it's zero */
1701 if (player->num_dynamic_pad)
1702 player->num_dynamic_pad--;
1704 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1706 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1707 __mmplayer_pipeline_complete(NULL, player);
1711 MMPLAYER_FREEIF(caps_str);
1714 gst_caps_unref(caps);
1720 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1722 int required_angle = 0; /* Angle required for straight view */
1723 int rotation_angle = 0;
1725 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1726 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1728 /* Counter clockwise */
1729 switch (orientation) {
1734 required_angle = 270;
1737 required_angle = 180;
1740 required_angle = 90;
1744 rotation_angle = display_angle + required_angle;
1745 if (rotation_angle >= 360)
1746 rotation_angle -= 360;
1748 /* chech if supported or not */
1749 if (rotation_angle % 90) {
1750 LOGD("not supported rotation angle = %d", rotation_angle);
1754 switch (rotation_angle) {
1756 *value = MM_DISPLAY_ROTATION_NONE;
1759 *value = MM_DISPLAY_ROTATION_90;
1762 *value = MM_DISPLAY_ROTATION_180;
1765 *value = MM_DISPLAY_ROTATION_270;
1769 LOGD("setting rotation property value : %d", *value);
1775 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1777 /* check video sinkbin is created */
1778 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1780 player->pipeline->videobin &&
1781 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1782 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1783 MM_ERROR_PLAYER_NOT_INITIALIZED);
1785 return MM_ERROR_NONE;
1789 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1791 int display_rotation = 0;
1792 gchar *org_orient = NULL;
1793 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1796 LOGE("cannot get content attribute");
1797 return MM_ERROR_PLAYER_INTERNAL;
1800 if (display_angle) {
1801 /* update user roation */
1802 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1804 /* Counter clockwise */
1805 switch (display_rotation) {
1806 case MM_DISPLAY_ROTATION_NONE:
1809 case MM_DISPLAY_ROTATION_90:
1810 *display_angle = 90;
1812 case MM_DISPLAY_ROTATION_180:
1813 *display_angle = 180;
1815 case MM_DISPLAY_ROTATION_270:
1816 *display_angle = 270;
1819 LOGW("wrong angle type : %d", display_rotation);
1822 LOGD("check user angle: %d", *display_angle);
1826 /* Counter clockwise */
1827 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1830 if (!strcmp(org_orient, "rotate-90"))
1832 else if (!strcmp(org_orient, "rotate-180"))
1834 else if (!strcmp(org_orient, "rotate-270"))
1837 LOGD("original rotation is %s", org_orient);
1839 LOGD("content_video_orientation get fail");
1842 LOGD("check orientation: %d", *orientation);
1845 return MM_ERROR_NONE;
1849 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1851 int rotation_value = 0;
1852 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1853 int display_angle = 0;
1856 /* check video sinkbin is created */
1857 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1860 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1862 /* get rotation value to set */
1863 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1864 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1865 LOGD("set video param : rotate %d", rotation_value);
1869 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1871 MMHandleType attrs = 0;
1875 /* check video sinkbin is created */
1876 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1879 attrs = MMPLAYER_GET_ATTRS(player);
1880 MMPLAYER_RETURN_IF_FAIL(attrs);
1882 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1883 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1884 LOGD("set video param : visible %d", visible);
1888 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1890 MMHandleType attrs = 0;
1891 int display_method = 0;
1894 /* check video sinkbin is created */
1895 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1898 attrs = MMPLAYER_GET_ATTRS(player);
1899 MMPLAYER_RETURN_IF_FAIL(attrs);
1901 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1902 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1903 LOGD("set video param : method %d", display_method);
1907 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1909 MMHandleType attrs = 0;
1910 void *handle = NULL;
1913 /* check video sinkbin is created */
1914 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1915 LOGW("There is no video sink");
1919 attrs = MMPLAYER_GET_ATTRS(player);
1920 MMPLAYER_RETURN_IF_FAIL(attrs);
1921 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1923 gst_video_overlay_set_video_roi_area(
1924 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1925 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1926 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1927 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1932 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1934 MMHandleType attrs = 0;
1935 void *handle = NULL;
1939 int win_roi_width = 0;
1940 int win_roi_height = 0;
1943 /* check video sinkbin is created */
1944 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1945 LOGW("There is no video sink");
1949 attrs = MMPLAYER_GET_ATTRS(player);
1950 MMPLAYER_RETURN_IF_FAIL(attrs);
1952 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1955 /* It should be set after setting window */
1956 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1957 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1958 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1959 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1961 /* After setting window handle, set display roi area */
1962 gst_video_overlay_set_display_roi_area(
1963 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1964 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1965 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1966 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1971 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1973 MMHandleType attrs = 0;
1974 void *handle = NULL;
1976 /* check video sinkbin is created */
1977 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1980 attrs = MMPLAYER_GET_ATTRS(player);
1981 MMPLAYER_RETURN_IF_FAIL(attrs);
1983 /* common case if using overlay surface */
1984 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1987 /* default is using wl_surface_id */
1988 unsigned int wl_surface_id = 0;
1989 wl_surface_id = *(int *)handle;
1990 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1991 gst_video_overlay_set_wl_window_wl_surface_id(
1992 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1995 /* FIXIT : is it error case? */
1996 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2001 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2003 gboolean update_all_param = FALSE;
2006 /* check video sinkbin is created */
2007 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2008 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2010 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2011 LOGE("can not find tizenwlsink");
2012 return MM_ERROR_PLAYER_INTERNAL;
2015 LOGD("param_name : %s", param_name);
2016 if (!g_strcmp0(param_name, "update_all_param"))
2017 update_all_param = TRUE;
2019 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2020 __mmplayer_video_param_set_display_overlay(player);
2021 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2022 __mmplayer_video_param_set_display_method(player);
2023 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2024 __mmplayer_video_param_set_display_visible(player);
2025 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2026 __mmplayer_video_param_set_display_rotation(player);
2027 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2028 __mmplayer_video_param_set_roi_area(player);
2029 if (update_all_param)
2030 __mmplayer_video_param_set_video_roi_area(player);
2032 return MM_ERROR_NONE;
2036 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2038 MMHandleType attrs = 0;
2039 int surface_type = 0;
2040 int ret = MM_ERROR_NONE;
2044 /* check video sinkbin is created */
2045 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2046 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2048 attrs = MMPLAYER_GET_ATTRS(player);
2050 LOGE("cannot get content attribute");
2051 return MM_ERROR_PLAYER_INTERNAL;
2053 LOGD("param_name : %s", param_name);
2055 /* update display surface */
2056 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2057 LOGD("check display surface type attribute: %d", surface_type);
2059 /* configuring display */
2060 switch (surface_type) {
2061 case MM_DISPLAY_SURFACE_OVERLAY:
2063 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2064 if (ret != MM_ERROR_NONE)
2072 return MM_ERROR_NONE;
2076 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2078 gboolean disable_overlay = FALSE;
2079 mmplayer_t *player = (mmplayer_t *)hplayer;
2080 int ret = MM_ERROR_NONE;
2083 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2084 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2085 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2086 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2088 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2089 LOGW("Display control is not supported");
2090 return MM_ERROR_PLAYER_INTERNAL;
2093 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2095 if (audio_only == (bool)disable_overlay) {
2096 LOGE("It's the same with current setting: (%d)", audio_only);
2097 return MM_ERROR_NONE;
2101 LOGE("disable overlay");
2102 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2104 /* release overlay resource */
2105 if (player->video_overlay_resource != NULL) {
2106 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2107 player->video_overlay_resource);
2108 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2109 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2112 player->video_overlay_resource = NULL;
2115 ret = mm_resource_manager_commit(player->resource_manager);
2116 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2117 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2121 /* mark video overlay for acquire */
2122 if (player->video_overlay_resource == NULL) {
2123 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2124 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2125 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2126 &player->video_overlay_resource);
2127 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2128 LOGE("could not prepare for video_overlay resource");
2133 player->interrupted_by_resource = FALSE;
2134 /* acquire resources for video overlay */
2135 ret = mm_resource_manager_commit(player->resource_manager);
2136 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2137 LOGE("could not acquire resources for video playing");
2141 LOGD("enable overlay");
2142 __mmplayer_video_param_set_display_overlay(player);
2143 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2148 return MM_ERROR_NONE;
2152 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2154 mmplayer_t *player = (mmplayer_t *)hplayer;
2155 gboolean disable_overlay = FALSE;
2159 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2160 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2161 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2162 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2163 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2165 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2166 LOGW("Display control is not supported");
2167 return MM_ERROR_PLAYER_INTERNAL;
2170 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2172 *paudio_only = (bool)disable_overlay;
2174 LOGD("audio_only : %d", *paudio_only);
2178 return MM_ERROR_NONE;
2182 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2184 GList *bucket = element_bucket;
2185 mmplayer_gst_element_t *element = NULL;
2186 mmplayer_gst_element_t *prv_element = NULL;
2187 GstElement *tee_element = NULL;
2188 gint successful_link_count = 0;
2192 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2194 prv_element = (mmplayer_gst_element_t *)bucket->data;
2195 bucket = bucket->next;
2197 for (; bucket; bucket = bucket->next) {
2198 element = (mmplayer_gst_element_t *)bucket->data;
2200 if (element && element->gst) {
2201 if (prv_element && prv_element->gst) {
2202 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2204 prv_element->gst = tee_element;
2206 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2207 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2208 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2212 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2213 LOGD("linking [%s] to [%s] success",
2214 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2215 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2216 successful_link_count++;
2217 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2218 LOGD("keep audio-tee element for next audio pipeline branch");
2219 tee_element = prv_element->gst;
2222 LOGD("linking [%s] to [%s] failed",
2223 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2224 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2230 prv_element = element;
2235 return successful_link_count;
2239 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2241 GList *bucket = element_bucket;
2242 mmplayer_gst_element_t *element = NULL;
2243 int successful_add_count = 0;
2247 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2248 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2250 for (; bucket; bucket = bucket->next) {
2251 element = (mmplayer_gst_element_t *)bucket->data;
2253 if (element && element->gst) {
2254 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2255 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2256 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2257 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2260 successful_add_count++;
2266 return successful_add_count;
2270 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2272 mmplayer_t *player = (mmplayer_t *)data;
2273 GstCaps *caps = NULL;
2274 GstStructure *str = NULL;
2276 gboolean caps_ret = TRUE;
2280 MMPLAYER_RETURN_IF_FAIL(pad);
2281 MMPLAYER_RETURN_IF_FAIL(unused);
2282 MMPLAYER_RETURN_IF_FAIL(data);
2284 caps = gst_pad_get_current_caps(pad);
2288 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2292 LOGD("name = %s", name);
2294 if (strstr(name, "audio")) {
2295 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2297 if (player->audio_stream_changed_cb) {
2298 LOGE("call the audio stream changed cb");
2299 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2301 } else if (strstr(name, "video")) {
2302 if ((name = gst_structure_get_string(str, "format")))
2303 player->set_mode.video_zc = name[0] == 'S';
2305 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2307 if (player->video_stream_changed_cb) {
2308 LOGE("call the video stream changed cb");
2309 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2312 LOGW("invalid caps info");
2317 gst_caps_unref(caps);
2325 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2330 MMPLAYER_RETURN_IF_FAIL(player);
2332 if (player->audio_stream_buff_list) {
2333 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2334 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2337 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2338 __mmplayer_audio_stream_send_data(player, tmp);
2340 MMPLAYER_FREEIF(tmp->pcm_data);
2341 MMPLAYER_FREEIF(tmp);
2344 g_list_free(player->audio_stream_buff_list);
2345 player->audio_stream_buff_list = NULL;
2352 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2354 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2357 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2359 audio_stream.bitrate = a_buffer->bitrate;
2360 audio_stream.channel = a_buffer->channel;
2361 audio_stream.depth = a_buffer->depth;
2362 audio_stream.is_little_endian = a_buffer->is_little_endian;
2363 audio_stream.channel_mask = a_buffer->channel_mask;
2364 audio_stream.data_size = a_buffer->data_size;
2365 audio_stream.data = a_buffer->pcm_data;
2366 audio_stream.pcm_format = a_buffer->pcm_format;
2368 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2369 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2375 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2377 mmplayer_t *player = (mmplayer_t *)data;
2378 const gchar *pcm_format = NULL;
2382 gint endianness = 0;
2383 guint64 channel_mask = 0;
2384 void *a_data = NULL;
2386 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2387 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2391 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2393 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2394 a_data = mapinfo.data;
2395 a_size = mapinfo.size;
2397 GstCaps *caps = gst_pad_get_current_caps(pad);
2398 GstStructure *structure = gst_caps_get_structure(caps, 0);
2400 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2401 pcm_format = gst_structure_get_string(structure, "format");
2402 gst_structure_get_int(structure, "rate", &rate);
2403 gst_structure_get_int(structure, "channels", &channel);
2404 gst_structure_get_int(structure, "depth", &depth);
2405 gst_structure_get_int(structure, "endianness", &endianness);
2406 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2407 gst_caps_unref(GST_CAPS(caps));
2409 /* In case of the sync is false, use buffer list. *
2410 * The num of buffer list depends on the num of audio channels */
2411 if (player->audio_stream_buff_list) {
2412 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2413 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2415 if (channel_mask == tmp->channel_mask) {
2416 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2417 if (tmp->data_size + a_size < tmp->buff_size) {
2418 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2419 tmp->data_size += a_size;
2421 /* send data to client */
2422 __mmplayer_audio_stream_send_data(player, tmp);
2424 if (a_size > tmp->buff_size) {
2425 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2426 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2427 if (tmp->pcm_data == NULL) {
2428 LOGE("failed to realloc data.");
2431 tmp->buff_size = a_size;
2433 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2434 memcpy(tmp->pcm_data, a_data, a_size);
2435 tmp->data_size = a_size;
2440 LOGE("data is empty in list.");
2446 /* create new audio stream data for newly found audio channel */
2447 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2448 if (a_buffer == NULL) {
2449 LOGE("failed to alloc data.");
2452 a_buffer->bitrate = rate;
2453 a_buffer->channel = channel;
2454 a_buffer->depth = depth;
2455 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2456 a_buffer->channel_mask = channel_mask;
2457 a_buffer->data_size = a_size;
2458 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2460 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2461 /* If sync is FALSE, use buffer list to reduce the IPC. */
2462 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2463 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2464 if (a_buffer->pcm_data == NULL) {
2465 LOGE("failed to alloc data.");
2466 MMPLAYER_FREEIF(a_buffer);
2469 memcpy(a_buffer->pcm_data, a_data, a_size);
2470 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2471 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2473 /* If sync is TRUE, send data directly. */
2474 a_buffer->pcm_data = a_data;
2475 __mmplayer_audio_stream_send_data(player, a_buffer);
2476 MMPLAYER_FREEIF(a_buffer);
2480 gst_buffer_unmap(buffer, &mapinfo);
2485 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2487 mmplayer_t *player = (mmplayer_t *)data;
2488 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2489 GstPad *sinkpad = NULL;
2490 GstElement *queue = NULL, *sink = NULL;
2493 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2495 queue = gst_element_factory_make("queue", NULL);
2496 if (queue == NULL) {
2497 LOGD("fail make queue");
2501 sink = gst_element_factory_make("fakesink", NULL);
2503 LOGD("fail make fakesink");
2507 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2509 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2510 LOGW("failed to link queue & sink");
2514 sinkpad = gst_element_get_static_pad(queue, "sink");
2516 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2517 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2521 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2523 gst_object_unref(sinkpad);
2524 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2525 g_object_set(sink, "sync", TRUE, NULL);
2526 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2528 /* keep the first sink reference only */
2529 if (!audiobin[MMPLAYER_A_SINK].gst) {
2530 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2531 audiobin[MMPLAYER_A_SINK].gst = sink;
2534 gst_element_set_state(sink, GST_STATE_PAUSED);
2535 gst_element_set_state(queue, GST_STATE_PAUSED);
2537 _mmplayer_add_signal_connection(player,
2539 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2541 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2544 __mmplayer_add_sink(player, sink);
2550 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2552 gst_object_unref(GST_OBJECT(queue));
2556 gst_object_unref(GST_OBJECT(sink));
2560 gst_object_unref(GST_OBJECT(sinkpad));
2568 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2570 #define MAX_PROPS_LEN 128
2571 gint latency_mode = 0;
2572 gchar *stream_type = NULL;
2573 gchar *latency = NULL;
2575 gchar stream_props[MAX_PROPS_LEN] = {0,};
2576 GstStructure *props = NULL;
2579 * It should be set after player creation through attribute.
2580 * But, it can not be changed during playing.
2583 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2585 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2586 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2589 LOGE("stream_type is null.");
2591 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2592 stream_type, stream_id);
2593 props = gst_structure_from_string(stream_props, NULL);
2594 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2595 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2596 gst_structure_free(props);
2599 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2601 switch (latency_mode) {
2602 case AUDIO_LATENCY_MODE_LOW:
2603 latency = g_strndup("low", 3);
2605 case AUDIO_LATENCY_MODE_MID:
2606 latency = g_strndup("mid", 3);
2608 case AUDIO_LATENCY_MODE_HIGH:
2609 latency = g_strndup("high", 4);
2613 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2617 LOGD("audiosink property - latency=%s", latency);
2619 MMPLAYER_FREEIF(latency);
2625 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2627 mmplayer_gst_element_t *audiobin = NULL;
2630 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2632 audiobin = player->pipeline->audiobin;
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2635 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2636 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2638 if (player->video360_yaw_radians <= M_PI &&
2639 player->video360_yaw_radians >= -M_PI &&
2640 player->video360_pitch_radians <= M_PI_2 &&
2641 player->video360_pitch_radians >= -M_PI_2) {
2642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2643 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2644 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2645 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2647 "source-orientation-y", player->video360_metadata.init_view_heading,
2648 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2655 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2657 mmplayer_gst_element_t *audiobin = NULL;
2658 GstPad *sink_pad = NULL;
2659 GstCaps *acaps = NULL;
2661 int pitch_control = 0;
2662 double pitch_value = 1.0;
2665 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2666 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2668 audiobin = player->pipeline->audiobin;
2670 LOGD("make element for normal audio playback");
2672 /* audio bin structure for playback. {} means optional.
2673 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2675 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2676 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2679 /* for pitch control */
2680 mm_attrs_multiple_get(player->attrs, NULL,
2681 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2682 MM_PLAYER_PITCH_VALUE, &pitch_value,
2685 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2686 if (pitch_control && (player->videodec_linked == 0)) {
2687 GstElementFactory *factory;
2689 factory = gst_element_factory_find("pitch");
2691 gst_object_unref(factory);
2694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2697 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2700 LOGW("there is no pitch element");
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2707 /* replaygain volume */
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2709 if (player->sound.rg_enable)
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2712 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2717 /* for logical volume control */
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2721 if (player->sound.mute) {
2722 LOGD("mute enabled");
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2726 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2728 /* audio effect element. if audio effect is enabled */
2729 if ((strcmp(player->ini.audioeffect_element, ""))
2731 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2734 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2736 if ((!player->bypass_audio_effect)
2737 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2738 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2739 if (!_mmplayer_audio_effect_custom_apply(player))
2740 LOGI("apply audio effect(custom) setting success");
2744 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2745 && (player->set_mode.rich_audio)) {
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2750 /* create audio sink */
2751 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2752 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2753 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2755 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2756 if (player->is_360_feature_enabled &&
2757 player->is_content_spherical &&
2759 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2760 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2761 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2763 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2765 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2767 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2768 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2769 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2770 gst_caps_unref(acaps);
2772 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2774 player->is_openal_plugin_used = TRUE;
2776 if (player->is_360_feature_enabled && player->is_content_spherical)
2777 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2778 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2781 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2782 (player->videodec_linked && player->ini.use_system_clock)) {
2783 LOGD("system clock will be used.");
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2787 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2788 __mmplayer_gst_set_pulsesink_property(player);
2789 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2790 __mmplayer_gst_set_openalsink_property(player);
2793 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2796 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2797 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2798 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2799 gst_object_unref(GST_OBJECT(sink_pad));
2801 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2804 return MM_ERROR_NONE;
2806 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2808 return MM_ERROR_PLAYER_INTERNAL;
2812 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2814 mmplayer_gst_element_t *audiobin = NULL;
2815 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2817 gchar *dst_format = NULL;
2819 int dst_samplerate = 0;
2820 int dst_channels = 0;
2821 GstCaps *caps = NULL;
2822 char *caps_str = NULL;
2825 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2826 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2828 audiobin = player->pipeline->audiobin;
2830 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2832 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2834 [case 1] extract interleave audio pcm without playback
2835 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2836 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2838 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2840 [case 2] deinterleave for each channel without playback
2841 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2842 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2844 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2845 - fakesink (sync or not)
2848 [case 3] [case 1(sync only)] + playback
2849 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2851 * src - ... - tee - queue1 - playback path
2852 - queue2 - [case1 pipeline with sync]
2854 [case 4] [case 2(sync only)] + playback
2855 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2857 * src - ... - tee - queue1 - playback path
2858 - queue2 - [case2 pipeline with sync]
2862 /* 1. create tee and playback path
2863 'tee' should be added at first to copy the decoded stream
2865 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2866 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2867 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2869 /* tee - path 1 : for playback path */
2870 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2871 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2873 /* tee - path 2 : for extract path */
2874 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2875 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2878 /* if there is tee, 'tee - path 2' is linked here */
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2885 /* 2. decide the extract pcm format */
2886 mm_attrs_multiple_get(player->attrs, NULL,
2887 "pcm_audioformat", &dst_format, &dst_len,
2888 "pcm_extraction_samplerate", &dst_samplerate,
2889 "pcm_extraction_channels", &dst_channels,
2892 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2893 dst_format, dst_len, dst_samplerate, dst_channels);
2895 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2896 mm_attrs_multiple_get(player->attrs, NULL,
2897 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2898 "content_audio_samplerate", &dst_samplerate,
2899 "content_audio_channels", &dst_channels,
2902 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2903 dst_format, dst_len, dst_samplerate, dst_channels);
2905 /* If there is no enough information, set it to platform default value. */
2906 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2907 LOGD("set platform default format");
2908 dst_format = DEFAULT_PCM_OUT_FORMAT;
2910 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2911 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2914 /* 3. create capsfilter */
2915 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2916 caps = gst_caps_new_simple("audio/x-raw",
2917 "format", G_TYPE_STRING, dst_format,
2918 "rate", G_TYPE_INT, dst_samplerate,
2919 "channels", G_TYPE_INT, dst_channels,
2922 caps_str = gst_caps_to_string(caps);
2923 LOGD("new caps : %s", caps_str);
2925 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2928 gst_caps_unref(caps);
2929 MMPLAYER_FREEIF(caps_str);
2931 /* 4-1. create deinterleave to extract pcm for each channel */
2932 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2933 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2934 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2936 /* audiosink will be added after getting signal for each channel */
2937 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2938 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2940 /* 4-2. create fakesink to extract interlevaed pcm */
2941 LOGD("add audio fakesink for interleaved audio");
2942 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2943 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2944 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2945 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2947 _mmplayer_add_signal_connection(player,
2948 G_OBJECT(audiobin[extract_sink_id].gst),
2949 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2951 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2954 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2958 return MM_ERROR_NONE;
2960 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2962 return MM_ERROR_PLAYER_INTERNAL;
2966 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2968 int ret = MM_ERROR_NONE;
2969 mmplayer_gst_element_t *audiobin = NULL;
2970 GList *element_bucket = NULL;
2973 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2974 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2976 audiobin = player->pipeline->audiobin;
2978 if (player->build_audio_offload) { /* skip all the audio filters */
2979 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2981 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2982 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2983 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2985 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2989 /* FIXME: need to mention the supportable condition at API reference */
2990 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2991 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2993 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2995 if (ret != MM_ERROR_NONE)
2998 LOGD("success to make audio bin element");
2999 *bucket = element_bucket;
3002 return MM_ERROR_NONE;
3005 LOGE("failed to make audio bin element");
3006 g_list_free(element_bucket);
3010 return MM_ERROR_PLAYER_INTERNAL;
3014 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3016 mmplayer_gst_element_t *first_element = NULL;
3017 mmplayer_gst_element_t *audiobin = NULL;
3019 GstPad *ghostpad = NULL;
3020 GList *element_bucket = NULL;
3024 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3027 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3029 LOGE("failed to allocate memory for audiobin");
3030 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3034 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3035 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3036 if (!audiobin[MMPLAYER_A_BIN].gst) {
3037 LOGE("failed to create audiobin");
3042 player->pipeline->audiobin = audiobin;
3044 /* create audio filters and audiosink */
3045 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3048 /* adding created elements to bin */
3049 LOGD("adding created elements to bin");
3050 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3053 /* linking elements in the bucket by added order. */
3054 LOGD("Linking elements in the bucket by added order.");
3055 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3058 /* get first element's sinkpad for creating ghostpad */
3059 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3060 if (!first_element) {
3061 LOGE("failed to get first elem");
3065 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3067 LOGE("failed to get pad from first element of audiobin");
3071 ghostpad = gst_ghost_pad_new("sink", pad);
3073 LOGE("failed to create ghostpad");
3077 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3078 LOGE("failed to add ghostpad to audiobin");
3082 gst_object_unref(pad);
3084 g_list_free(element_bucket);
3087 return MM_ERROR_NONE;
3090 LOGD("ERROR : releasing audiobin");
3093 gst_object_unref(GST_OBJECT(pad));
3096 gst_object_unref(GST_OBJECT(ghostpad));
3099 g_list_free(element_bucket);
3101 /* release element which are not added to bin */
3102 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3103 /* NOTE : skip bin */
3104 if (audiobin[i].gst) {
3105 GstObject *parent = NULL;
3106 parent = gst_element_get_parent(audiobin[i].gst);
3109 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3110 audiobin[i].gst = NULL;
3112 gst_object_unref(GST_OBJECT(parent));
3116 /* release audiobin with it's childs */
3117 if (audiobin[MMPLAYER_A_BIN].gst)
3118 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3120 MMPLAYER_FREEIF(audiobin);
3122 player->pipeline->audiobin = NULL;
3124 return MM_ERROR_PLAYER_INTERNAL;
3128 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3130 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3134 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3136 int ret = MM_ERROR_NONE;
3138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3139 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3141 MMPLAYER_VIDEO_BO_LOCK(player);
3143 if (player->video_bo_list) {
3144 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3145 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3146 if (tmp && tmp->bo == bo) {
3148 LOGD("release bo %p", bo);
3149 tbm_bo_unref(tmp->bo);
3150 MMPLAYER_VIDEO_BO_UNLOCK(player);
3151 MMPLAYER_VIDEO_BO_SIGNAL(player);
3156 /* hw codec is running or the list was reset for DRC. */
3157 LOGW("there is no bo list.");
3159 MMPLAYER_VIDEO_BO_UNLOCK(player);
3161 LOGW("failed to find bo %p", bo);
3166 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3171 MMPLAYER_RETURN_IF_FAIL(player);
3173 MMPLAYER_VIDEO_BO_LOCK(player);
3174 if (player->video_bo_list) {
3175 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3176 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3177 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3180 tbm_bo_unref(tmp->bo);
3184 g_list_free(player->video_bo_list);
3185 player->video_bo_list = NULL;
3187 player->video_bo_size = 0;
3188 MMPLAYER_VIDEO_BO_UNLOCK(player);
3195 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3198 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3199 gboolean ret = TRUE;
3201 /* check DRC, if it is, destroy the prev bo list to create again */
3202 if (player->video_bo_size != size) {
3203 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3204 __mmplayer_video_stream_destroy_bo_list(player);
3205 player->video_bo_size = size;
3208 MMPLAYER_VIDEO_BO_LOCK(player);
3210 if ((!player->video_bo_list) ||
3211 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3213 /* create bo list */
3215 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3217 if (player->video_bo_list) {
3218 /* if bo list did not created all, try it again. */
3219 idx = g_list_length(player->video_bo_list);
3220 LOGD("bo list exist(len: %d)", idx);
3223 for (; idx < player->ini.num_of_video_bo; idx++) {
3224 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3226 LOGE("Fail to alloc bo_info.");
3229 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3231 LOGE("Fail to tbm_bo_alloc.");
3232 MMPLAYER_FREEIF(bo_info);
3235 bo_info->used = FALSE;
3236 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3239 /* update video num buffers */
3240 player->video_num_buffers = idx;
3241 if (idx == player->ini.num_of_video_bo)
3242 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3245 MMPLAYER_VIDEO_BO_UNLOCK(player);
3249 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3253 /* get bo from list*/
3254 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3255 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3256 if (tmp && (tmp->used == FALSE)) {
3257 LOGD("found bo %p to use", tmp->bo);
3259 MMPLAYER_VIDEO_BO_UNLOCK(player);
3260 return tbm_bo_ref(tmp->bo);
3264 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3265 MMPLAYER_VIDEO_BO_UNLOCK(player);
3269 if (player->ini.video_bo_timeout <= 0) {
3270 MMPLAYER_VIDEO_BO_WAIT(player);
3272 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3273 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3280 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3282 mmplayer_t *player = (mmplayer_t *)data;
3284 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3286 /* send prerolled pkt */
3287 player->video_stream_prerolled = false;
3289 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3291 /* not to send prerolled pkt again */
3292 player->video_stream_prerolled = true;
3296 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3298 mmplayer_t *player = (mmplayer_t *)data;
3299 mmplayer_video_decoded_data_info_t *stream = NULL;
3300 GstMemory *mem = NULL;
3303 MMPLAYER_RETURN_IF_FAIL(player);
3304 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3306 if (player->video_stream_prerolled) {
3307 player->video_stream_prerolled = false;
3308 LOGD("skip the prerolled pkt not to send it again");
3312 /* clear stream data structure */
3313 stream = __mmplayer_create_stream_from_pad(pad);
3315 LOGE("failed to alloc stream");
3319 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3321 /* set size and timestamp */
3322 mem = gst_buffer_peek_memory(buffer, 0);
3323 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3324 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3326 /* check zero-copy */
3327 if (player->set_mode.video_zc &&
3328 player->set_mode.video_export &&
3329 gst_is_tizen_memory(mem)) {
3330 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3331 stream->internal_buffer = gst_buffer_ref(buffer);
3332 } else { /* sw codec */
3333 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3336 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3340 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3341 LOGE("failed to send video decoded data.");
3348 LOGE("release video stream resource.");
3349 if (gst_is_tizen_memory(mem)) {
3351 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3353 tbm_bo_unref(stream->bo[i]);
3356 /* unref gst buffer */
3357 if (stream->internal_buffer)
3358 gst_buffer_unref(stream->internal_buffer);
3361 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3363 MMPLAYER_FREEIF(stream);
3368 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3370 mmplayer_gst_element_t *videobin = NULL;
3373 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3375 videobin = player->pipeline->videobin;
3377 /* Set spatial media metadata and/or user settings to the element.
3379 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3380 "projection-type", player->video360_metadata.projection_type, NULL);
3382 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3383 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3385 if (player->video360_metadata.full_pano_width_pixels &&
3386 player->video360_metadata.full_pano_height_pixels &&
3387 player->video360_metadata.cropped_area_image_width &&
3388 player->video360_metadata.cropped_area_image_height) {
3389 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3390 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3391 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3392 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3393 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3394 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3395 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3399 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3400 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3401 "horizontal-fov", player->video360_horizontal_fov,
3402 "vertical-fov", player->video360_vertical_fov, NULL);
3405 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3406 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3407 "zoom", 1.0f / player->video360_zoom, NULL);
3410 if (player->video360_yaw_radians <= M_PI &&
3411 player->video360_yaw_radians >= -M_PI &&
3412 player->video360_pitch_radians <= M_PI_2 &&
3413 player->video360_pitch_radians >= -M_PI_2) {
3414 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3415 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3416 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3417 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3418 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3419 "pose-yaw", player->video360_metadata.init_view_heading,
3420 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3423 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3424 "passthrough", !player->is_video360_enabled, NULL);
3431 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3433 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3434 GList *element_bucket = NULL;
3437 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3439 /* create video360 filter */
3440 if (player->is_360_feature_enabled && player->is_content_spherical) {
3441 LOGD("create video360 element");
3442 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3443 __mmplayer_gst_set_video360_property(player);
3447 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3448 LOGD("skip creating the videoconv and rotator");
3449 return MM_ERROR_NONE;
3452 /* in case of sw codec & overlay surface type, except 360 playback.
3453 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3454 LOGD("create video converter: %s", video_csc);
3455 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3458 *bucket = element_bucket;
3460 return MM_ERROR_NONE;
3462 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3463 g_list_free(element_bucket);
3467 return MM_ERROR_PLAYER_INTERNAL;
3471 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3473 gchar *factory_name = NULL;
3475 switch (surface_type) {
3476 case MM_DISPLAY_SURFACE_OVERLAY:
3477 if (strlen(player->ini.videosink_element_overlay) > 0)
3478 factory_name = player->ini.videosink_element_overlay;
3480 case MM_DISPLAY_SURFACE_REMOTE:
3481 case MM_DISPLAY_SURFACE_NULL:
3482 if (strlen(player->ini.videosink_element_fake) > 0)
3483 factory_name = player->ini.videosink_element_fake;
3486 LOGE("unidentified surface type");
3490 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3491 return factory_name;
3495 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3497 gchar *factory_name = NULL;
3498 mmplayer_gst_element_t *videobin = NULL;
3503 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3505 videobin = player->pipeline->videobin;
3506 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3508 attrs = MMPLAYER_GET_ATTRS(player);
3510 LOGE("cannot get content attribute");
3511 return MM_ERROR_PLAYER_INTERNAL;
3514 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3515 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3516 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3518 /* support shard memory with S/W codec on HawkP */
3519 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3520 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3521 "use-tbm", use_tbm, NULL);
3525 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3526 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3529 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3531 LOGD("disable last-sample");
3532 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3535 if (player->set_mode.video_export) {
3537 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3538 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3539 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3541 _mmplayer_add_signal_connection(player,
3542 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3543 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3545 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3548 _mmplayer_add_signal_connection(player,
3549 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3550 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3552 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3556 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3557 return MM_ERROR_PLAYER_INTERNAL;
3559 if (videobin[MMPLAYER_V_SINK].gst) {
3560 GstPad *sink_pad = NULL;
3561 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3563 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3564 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3565 gst_object_unref(GST_OBJECT(sink_pad));
3567 LOGE("failed to get sink pad from videosink");
3571 return MM_ERROR_NONE;
3576 * - video overlay surface(arm/x86) : tizenwlsink
3579 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3582 GList *element_bucket = NULL;
3583 mmplayer_gst_element_t *first_element = NULL;
3584 mmplayer_gst_element_t *videobin = NULL;
3585 gchar *videosink_factory_name = NULL;
3588 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3591 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3593 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3595 player->pipeline->videobin = videobin;
3598 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3599 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3600 if (!videobin[MMPLAYER_V_BIN].gst) {
3601 LOGE("failed to create videobin");
3605 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3608 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3609 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3611 /* additional setting for sink plug-in */
3612 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3613 LOGE("failed to set video property");
3617 /* store it as it's sink element */
3618 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3620 /* adding created elements to bin */
3621 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3622 LOGE("failed to add elements");
3626 /* Linking elements in the bucket by added order */
3627 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3628 LOGE("failed to link elements");
3632 /* get first element's sinkpad for creating ghostpad */
3633 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3634 if (!first_element) {
3635 LOGE("failed to get first element from bucket");
3639 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3641 LOGE("failed to get pad from first element");
3645 /* create ghostpad */
3646 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3647 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3648 LOGE("failed to add ghostpad to videobin");
3651 gst_object_unref(pad);
3653 /* done. free allocated variables */
3654 g_list_free(element_bucket);
3658 return MM_ERROR_NONE;
3661 LOGE("ERROR : releasing videobin");
3662 g_list_free(element_bucket);
3665 gst_object_unref(GST_OBJECT(pad));
3667 /* release videobin with it's childs */
3668 if (videobin[MMPLAYER_V_BIN].gst)
3669 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3671 MMPLAYER_FREEIF(videobin);
3672 player->pipeline->videobin = NULL;
3674 return MM_ERROR_PLAYER_INTERNAL;
3678 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3680 GList *element_bucket = NULL;
3681 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3683 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3684 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3685 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3686 "signal-handoffs", FALSE,
3689 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3690 _mmplayer_add_signal_connection(player,
3691 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3692 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3694 G_CALLBACK(__mmplayer_update_subtitle),
3697 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3698 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3700 if (!player->play_subtitle) {
3701 LOGD("add textbin sink as sink element of whole pipeline.");
3702 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3705 /* adding created elements to bin */
3706 LOGD("adding created elements to bin");
3707 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3708 LOGE("failed to add elements");
3712 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3713 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3714 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3716 /* linking elements in the bucket by added order. */
3717 LOGD("Linking elements in the bucket by added order.");
3718 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3719 LOGE("failed to link elements");
3723 /* done. free allocated variables */
3724 g_list_free(element_bucket);
3726 if (textbin[MMPLAYER_T_QUEUE].gst) {
3728 GstPad *ghostpad = NULL;
3730 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3732 LOGE("failed to get sink pad of text queue");
3736 ghostpad = gst_ghost_pad_new("text_sink", pad);
3737 gst_object_unref(pad);
3740 LOGE("failed to create ghostpad of textbin");
3744 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3745 LOGE("failed to add ghostpad to textbin");
3746 gst_object_unref(ghostpad);
3751 return MM_ERROR_NONE;
3754 g_list_free(element_bucket);
3756 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3757 LOGE("remove textbin sink from sink list");
3758 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3761 /* release element at __mmplayer_gst_create_text_sink_bin */
3762 return MM_ERROR_PLAYER_INTERNAL;
3766 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3768 mmplayer_gst_element_t *textbin = NULL;
3769 GList *element_bucket = NULL;
3770 int surface_type = 0;
3775 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3778 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3780 LOGE("failed to allocate memory for textbin");
3781 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3785 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3786 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3787 if (!textbin[MMPLAYER_T_BIN].gst) {
3788 LOGE("failed to create textbin");
3793 player->pipeline->textbin = textbin;
3796 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3797 LOGD("surface type for subtitle : %d", surface_type);
3798 switch (surface_type) {
3799 case MM_DISPLAY_SURFACE_OVERLAY:
3800 case MM_DISPLAY_SURFACE_NULL:
3801 case MM_DISPLAY_SURFACE_REMOTE:
3802 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3803 LOGE("failed to make plain text elements");
3814 return MM_ERROR_NONE;
3818 LOGD("ERROR : releasing textbin");
3820 g_list_free(element_bucket);
3822 /* release signal */
3823 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3825 /* release element which are not added to bin */
3826 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3827 /* NOTE : skip bin */
3828 if (textbin[i].gst) {
3829 GstObject *parent = NULL;
3830 parent = gst_element_get_parent(textbin[i].gst);
3833 gst_object_unref(GST_OBJECT(textbin[i].gst));
3834 textbin[i].gst = NULL;
3836 gst_object_unref(GST_OBJECT(parent));
3841 /* release textbin with it's childs */
3842 if (textbin[MMPLAYER_T_BIN].gst)
3843 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3845 MMPLAYER_FREEIF(player->pipeline->textbin);
3846 player->pipeline->textbin = NULL;
3849 return MM_ERROR_PLAYER_INTERNAL;
3853 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3855 mmplayer_gst_element_t *mainbin = NULL;
3856 mmplayer_gst_element_t *textbin = NULL;
3857 MMHandleType attrs = 0;
3858 GstElement *subsrc = NULL;
3859 GstElement *subparse = NULL;
3860 gchar *subtitle_uri = NULL;
3861 const gchar *charset = NULL;
3867 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3869 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3871 mainbin = player->pipeline->mainbin;
3873 attrs = MMPLAYER_GET_ATTRS(player);
3875 LOGE("cannot get content attribute");
3876 return MM_ERROR_PLAYER_INTERNAL;
3879 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3880 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3881 LOGE("subtitle uri is not proper filepath.");
3882 return MM_ERROR_PLAYER_INVALID_URI;
3885 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3886 LOGE("failed to get storage info of subtitle path");
3887 return MM_ERROR_PLAYER_INVALID_URI;
3890 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3892 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3893 player->subtitle_language_list = NULL;
3894 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3896 /* create the subtitle source */
3897 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3899 LOGE("failed to create filesrc element");
3902 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3904 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3905 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3907 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3908 LOGW("failed to add queue");
3909 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3910 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3911 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3916 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3918 LOGE("failed to create subparse element");
3922 charset = _mmplayer_get_charset(subtitle_uri);
3924 LOGD("detected charset is %s", charset);
3925 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3928 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3929 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3931 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3932 LOGW("failed to add subparse");
3933 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3934 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3935 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3939 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3940 LOGW("failed to link subsrc and subparse");
3944 player->play_subtitle = TRUE;
3945 player->adjust_subtitle_pos = 0;
3947 LOGD("play subtitle using subtitle file");
3949 if (player->pipeline->textbin == NULL) {
3950 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3951 LOGE("failed to create text sink bin. continuing without text");
3955 textbin = player->pipeline->textbin;
3957 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3958 LOGW("failed to add textbin");
3960 /* release signal */
3961 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3963 /* release textbin with it's childs */
3964 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3965 MMPLAYER_FREEIF(player->pipeline->textbin);
3966 player->pipeline->textbin = textbin = NULL;
3970 LOGD("link text input selector and textbin ghost pad");
3972 player->textsink_linked = 1;
3973 player->external_text_idx = 0;
3974 LOGI("textsink is linked");
3976 textbin = player->pipeline->textbin;
3977 LOGD("text bin has been created. reuse it.");
3978 player->external_text_idx = 1;
3981 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3982 LOGW("failed to link subparse and textbin");
3986 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3988 LOGE("failed to get sink pad from textsink to probe data");
3992 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3993 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3995 gst_object_unref(pad);
3998 /* create dot. for debugging */
3999 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4002 return MM_ERROR_NONE;
4005 /* release text pipeline resource */
4006 player->textsink_linked = 0;
4008 /* release signal */
4009 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4011 if (player->pipeline->textbin) {
4012 LOGE("remove textbin");
4014 /* release textbin with it's childs */
4015 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4016 MMPLAYER_FREEIF(player->pipeline->textbin);
4017 player->pipeline->textbin = NULL;
4021 /* release subtitle elem */
4022 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4023 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4025 return MM_ERROR_PLAYER_INTERNAL;
4029 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4031 mmplayer_t *player = (mmplayer_t *)data;
4032 MMMessageParamType msg = {0, };
4033 GstClockTime duration = 0;
4034 gpointer text = NULL;
4035 guint text_size = 0;
4036 gboolean ret = TRUE;
4037 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4041 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4042 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4044 if (player->is_subtitle_force_drop) {
4045 LOGW("subtitle is dropped forcedly.");
4049 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4050 text = mapinfo.data;
4051 text_size = mapinfo.size;
4053 if (player->set_mode.subtitle_off) {
4054 LOGD("subtitle is OFF.");
4058 if (!text || (text_size == 0)) {
4059 LOGD("There is no subtitle to be displayed.");
4063 msg.data = (void *)text;
4065 duration = GST_BUFFER_DURATION(buffer);
4067 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4068 if (player->duration > GST_BUFFER_PTS(buffer))
4069 duration = player->duration - GST_BUFFER_PTS(buffer);
4072 LOGI("subtitle duration is invalid, subtitle duration change "
4073 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4075 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4077 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4079 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4080 gst_buffer_unmap(buffer, &mapinfo);
4087 static GstPadProbeReturn
4088 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4090 mmplayer_t *player = (mmplayer_t *)u_data;
4091 GstClockTime cur_timestamp = 0;
4092 gint64 adjusted_timestamp = 0;
4093 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4095 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4097 if (player->set_mode.subtitle_off) {
4098 LOGD("subtitle is OFF.");
4102 if (player->adjust_subtitle_pos == 0) {
4103 LOGD("nothing to do");
4107 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4108 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4110 if (adjusted_timestamp < 0) {
4111 LOGD("adjusted_timestamp under zero");
4116 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4117 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4118 GST_TIME_ARGS(cur_timestamp),
4119 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4121 return GST_PAD_PROBE_OK;
4125 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4129 /* check player and subtitlebin are created */
4130 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4131 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4133 if (position == 0) {
4134 LOGD("nothing to do");
4136 return MM_ERROR_NONE;
4139 /* check current postion */
4140 player->adjust_subtitle_pos = position;
4142 LOGD("save adjust_subtitle_pos in player");
4146 return MM_ERROR_NONE;
4150 * This function is to create audio or video pipeline for playing.
4152 * @param player [in] handle of player
4154 * @return This function returns zero on success.
4159 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4161 int ret = MM_ERROR_NONE;
4162 mmplayer_gst_element_t *mainbin = NULL;
4163 MMHandleType attrs = 0;
4166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4168 /* get profile attribute */
4169 attrs = MMPLAYER_GET_ATTRS(player);
4171 LOGE("failed to get content attribute");
4175 /* create pipeline handles */
4176 if (player->pipeline) {
4177 LOGE("pipeline should be released before create new one");
4181 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4182 if (player->pipeline == NULL)
4185 /* create mainbin */
4186 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4187 if (mainbin == NULL)
4190 /* create pipeline */
4191 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4192 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4193 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4194 LOGE("failed to create pipeline");
4199 player->pipeline->mainbin = mainbin;
4201 /* create the source and decoder elements */
4202 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4203 ret = _mmplayer_gst_build_es_pipeline(player);
4205 ret = _mmplayer_gst_build_pipeline(player);
4207 if (ret != MM_ERROR_NONE) {
4208 LOGE("failed to create some elements");
4212 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4213 if (__mmplayer_check_subtitle(player)
4214 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4215 LOGE("failed to create text pipeline");
4218 ret = _mmplayer_gst_add_bus_watch(player);
4219 if (ret != MM_ERROR_NONE) {
4220 LOGE("failed to add bus watch");
4225 return MM_ERROR_NONE;
4228 __mmplayer_gst_destroy_pipeline(player);
4229 return MM_ERROR_PLAYER_INTERNAL;
4233 __mmplayer_reset_gapless_state(mmplayer_t *player)
4236 MMPLAYER_RETURN_IF_FAIL(player
4238 && player->pipeline->audiobin
4239 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4241 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4248 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4251 int ret = MM_ERROR_NONE;
4255 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4257 /* cleanup stuffs */
4258 MMPLAYER_FREEIF(player->type);
4259 player->no_more_pad = FALSE;
4260 player->num_dynamic_pad = 0;
4261 player->demux_pad_index = 0;
4263 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4264 player->subtitle_language_list = NULL;
4265 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4267 __mmplayer_reset_gapless_state(player);
4269 if (player->streamer) {
4270 _mm_player_streaming_initialize(player->streamer, FALSE);
4271 _mm_player_streaming_destroy(player->streamer);
4272 player->streamer = NULL;
4275 /* cleanup unlinked mime type */
4276 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4277 MMPLAYER_FREEIF(player->unlinked_video_mime);
4278 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4280 /* cleanup running stuffs */
4281 _mmplayer_cancel_eos_timer(player);
4283 /* cleanup gst stuffs */
4284 if (player->pipeline) {
4285 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4286 GstTagList *tag_list = player->pipeline->tag_list;
4288 /* first we need to disconnect all signal hander */
4289 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4292 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4293 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4294 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4295 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4296 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4297 gst_object_unref(bus);
4299 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4300 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4301 if (ret != MM_ERROR_NONE) {
4302 LOGE("fail to change state to NULL");
4303 return MM_ERROR_PLAYER_INTERNAL;
4306 LOGW("succeeded in changing state to NULL");
4308 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4311 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4312 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4314 /* free avsysaudiosink
4315 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4316 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4318 MMPLAYER_FREEIF(audiobin);
4319 MMPLAYER_FREEIF(videobin);
4320 MMPLAYER_FREEIF(textbin);
4321 MMPLAYER_FREEIF(mainbin);
4325 gst_tag_list_unref(tag_list);
4327 MMPLAYER_FREEIF(player->pipeline);
4329 MMPLAYER_FREEIF(player->album_art);
4331 if (player->v_stream_caps) {
4332 gst_caps_unref(player->v_stream_caps);
4333 player->v_stream_caps = NULL;
4336 if (player->a_stream_caps) {
4337 gst_caps_unref(player->a_stream_caps);
4338 player->a_stream_caps = NULL;
4341 if (player->s_stream_caps) {
4342 gst_caps_unref(player->s_stream_caps);
4343 player->s_stream_caps = NULL;
4345 _mmplayer_track_destroy(player);
4347 if (player->sink_elements)
4348 g_list_free(player->sink_elements);
4349 player->sink_elements = NULL;
4351 if (player->bufmgr) {
4352 tbm_bufmgr_deinit(player->bufmgr);
4353 player->bufmgr = NULL;
4356 LOGW("finished destroy pipeline");
4364 __mmplayer_gst_realize(mmplayer_t *player)
4367 int ret = MM_ERROR_NONE;
4371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4373 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4375 ret = __mmplayer_gst_create_pipeline(player);
4377 LOGE("failed to create pipeline");
4381 /* set pipeline state to READY */
4382 /* NOTE : state change to READY must be performed sync. */
4383 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4384 ret = _mmplayer_gst_set_state(player,
4385 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4387 if (ret != MM_ERROR_NONE) {
4388 /* return error if failed to set state */
4389 LOGE("failed to set READY state");
4393 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4395 /* create dot before error-return. for debugging */
4396 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4404 __mmplayer_gst_unrealize(mmplayer_t *player)
4406 int ret = MM_ERROR_NONE;
4410 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4412 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4413 MMPLAYER_PRINT_STATE(player);
4415 /* release miscellaneous information */
4416 __mmplayer_release_misc(player);
4418 /* destroy pipeline */
4419 ret = __mmplayer_gst_destroy_pipeline(player);
4420 if (ret != MM_ERROR_NONE) {
4421 LOGE("failed to destory pipeline");
4425 /* release miscellaneous information.
4426 these info needs to be released after pipeline is destroyed. */
4427 __mmplayer_release_misc_post(player);
4429 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4437 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4442 LOGW("set_message_callback is called with invalid player handle");
4443 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4446 player->msg_cb = callback;
4447 player->msg_cb_param = user_param;
4449 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4453 return MM_ERROR_NONE;
4457 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4459 int ret = MM_ERROR_NONE;
4464 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4465 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4466 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4468 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4470 if (strstr(uri, "es_buff://")) {
4471 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4472 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4473 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4474 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4476 tmp = g_ascii_strdown(uri, strlen(uri));
4477 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4478 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4480 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4482 } else if (strstr(uri, "mms://")) {
4483 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4484 } else if ((path = strstr(uri, "mem://"))) {
4485 ret = __mmplayer_set_mem_uri(data, path, param);
4487 ret = __mmplayer_set_file_uri(data, uri);
4490 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4491 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4492 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4493 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4495 /* dump parse result */
4496 SECURE_LOGW("incoming uri : %s", uri);
4497 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4498 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4506 __mmplayer_can_do_interrupt(mmplayer_t *player)
4508 if (!player || !player->pipeline || !player->attrs) {
4509 LOGW("not initialized");
4513 if (player->audio_decoded_cb) {
4514 LOGW("not support in pcm extraction mode");
4518 /* check if seeking */
4519 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4520 MMMessageParamType msg_param;
4521 memset(&msg_param, 0, sizeof(MMMessageParamType));
4522 msg_param.code = MM_ERROR_PLAYER_SEEK;
4523 player->seek_state = MMPLAYER_SEEK_NONE;
4524 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4528 /* check other thread */
4529 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4530 LOGW("locked already, cmd state : %d", player->cmd);
4532 /* check application command */
4533 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4534 LOGW("playing.. should wait cmd lock then, will be interrupted");
4536 /* lock will be released at mrp_resource_release_cb() */
4537 MMPLAYER_CMD_LOCK(player);
4540 LOGW("nothing to do");
4543 LOGW("can interrupt immediately");
4547 FAILED: /* with CMD UNLOCKED */
4550 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4555 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4558 mmplayer_t *player = NULL;
4562 if (user_data == NULL) {
4563 LOGE("- user_data is null");
4566 player = (mmplayer_t *)user_data;
4568 /* do something to release resource here.
4569 * player stop and interrupt forwarding */
4570 if (!__mmplayer_can_do_interrupt(player)) {
4571 LOGW("no need to interrupt, so leave");
4573 MMMessageParamType msg = {0, };
4576 player->interrupted_by_resource = TRUE;
4578 /* get last play position */
4579 if (_mmplayer_gst_get_position(player, &pos) != MM_ERROR_NONE) {
4580 LOGW("failed to get play position.");
4582 msg.union_type = MM_MSG_UNION_TIME;
4583 msg.time.elapsed = pos;
4584 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4586 LOGD("video resource conflict so, resource will be freed by unrealizing");
4587 if (_mmplayer_unrealize((MMHandleType)player))
4588 LOGW("failed to unrealize");
4590 /* lock is called in __mmplayer_can_do_interrupt() */
4591 MMPLAYER_CMD_UNLOCK(player);
4594 if (res == player->video_overlay_resource)
4595 player->video_overlay_resource = FALSE;
4597 player->video_decoder_resource = FALSE;
4605 __mmplayer_initialize_video_roi(mmplayer_t *player)
4607 player->video_roi.scale_x = 0.0;
4608 player->video_roi.scale_y = 0.0;
4609 player->video_roi.scale_width = 1.0;
4610 player->video_roi.scale_height = 1.0;
4614 _mmplayer_create_player(MMHandleType handle)
4616 int ret = MM_ERROR_PLAYER_INTERNAL;
4617 bool enabled = false;
4619 mmplayer_t *player = MM_PLAYER_CAST(handle);
4623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4625 /* initialize player state */
4626 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4627 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4628 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4629 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4631 /* check current state */
4632 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4634 /* construct attributes */
4635 player->attrs = _mmplayer_construct_attribute(handle);
4637 if (!player->attrs) {
4638 LOGE("Failed to construct attributes");
4642 /* initialize gstreamer with configured parameter */
4643 if (!__mmplayer_init_gstreamer(player)) {
4644 LOGE("Initializing gstreamer failed");
4645 _mmplayer_deconstruct_attribute(handle);
4649 /* create lock. note that g_tread_init() has already called in gst_init() */
4650 g_mutex_init(&player->fsink_lock);
4652 /* create update tag lock */
4653 g_mutex_init(&player->update_tag_lock);
4655 /* create gapless play mutex */
4656 g_mutex_init(&player->gapless_play_thread_mutex);
4658 /* create gapless play cond */
4659 g_cond_init(&player->gapless_play_thread_cond);
4661 /* create gapless play thread */
4662 player->gapless_play_thread =
4663 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4664 if (!player->gapless_play_thread) {
4665 LOGE("failed to create gapless play thread");
4666 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4667 g_mutex_clear(&player->gapless_play_thread_mutex);
4668 g_cond_clear(&player->gapless_play_thread_cond);
4672 player->bus_msg_q = g_queue_new();
4673 if (!player->bus_msg_q) {
4674 LOGE("failed to create queue for bus_msg");
4675 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4679 ret = _mmplayer_initialize_video_capture(player);
4680 if (ret != MM_ERROR_NONE) {
4681 LOGE("failed to initialize video capture");
4685 /* initialize resource manager */
4686 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4687 __resource_release_cb, player, &player->resource_manager)
4688 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4689 LOGE("failed to initialize resource manager");
4690 ret = MM_ERROR_PLAYER_INTERNAL;
4694 /* create video bo lock and cond */
4695 g_mutex_init(&player->video_bo_mutex);
4696 g_cond_init(&player->video_bo_cond);
4698 /* create media stream callback mutex */
4699 g_mutex_init(&player->media_stream_cb_lock);
4701 /* create subtitle info lock and cond */
4702 g_mutex_init(&player->subtitle_info_mutex);
4703 g_cond_init(&player->subtitle_info_cond);
4705 player->streaming_type = STREAMING_SERVICE_NONE;
4707 /* give default value of audio effect setting */
4708 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4709 player->sound.rg_enable = false;
4710 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4712 player->play_subtitle = FALSE;
4713 player->has_closed_caption = FALSE;
4714 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4715 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4716 player->pending_resume = FALSE;
4717 if (player->ini.dump_element_keyword[0][0] == '\0')
4718 player->ini.set_dump_element_flag = FALSE;
4720 player->ini.set_dump_element_flag = TRUE;
4722 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4723 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4724 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4726 /* Set video360 settings to their defaults for just-created player.
4729 player->is_360_feature_enabled = FALSE;
4730 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4731 LOGI("spherical feature info: %d", enabled);
4733 player->is_360_feature_enabled = TRUE;
4735 LOGE("failed to get spherical feature info");
4738 player->is_content_spherical = FALSE;
4739 player->is_video360_enabled = TRUE;
4740 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4741 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4742 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4743 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4744 player->video360_zoom = 1.0f;
4745 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4746 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4748 __mmplayer_initialize_video_roi(player);
4750 /* set player state to null */
4751 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4752 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4756 return MM_ERROR_NONE;
4760 g_mutex_clear(&player->fsink_lock);
4761 /* free update tag lock */
4762 g_mutex_clear(&player->update_tag_lock);
4763 g_queue_free(player->bus_msg_q);
4764 player->bus_msg_q = NULL;
4765 /* free gapless play thread */
4766 if (player->gapless_play_thread) {
4767 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4768 player->gapless_play_thread_exit = TRUE;
4769 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4770 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4772 g_thread_join(player->gapless_play_thread);
4773 player->gapless_play_thread = NULL;
4775 g_mutex_clear(&player->gapless_play_thread_mutex);
4776 g_cond_clear(&player->gapless_play_thread_cond);
4779 /* release attributes */
4780 _mmplayer_deconstruct_attribute(handle);
4788 __mmplayer_init_gstreamer(mmplayer_t *player)
4790 static gboolean initialized = FALSE;
4791 static const int max_argc = 50;
4793 gchar **argv = NULL;
4794 gchar **argv2 = NULL;
4800 LOGD("gstreamer already initialized.");
4805 argc = malloc(sizeof(int));
4806 argv = malloc(sizeof(gchar *) * max_argc);
4807 argv2 = malloc(sizeof(gchar *) * max_argc);
4809 if (!argc || !argv || !argv2)
4812 memset(argv, 0, sizeof(gchar *) * max_argc);
4813 memset(argv2, 0, sizeof(gchar *) * max_argc);
4817 argv[0] = g_strdup("mmplayer");
4820 for (i = 0; i < 5; i++) {
4821 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4822 if (strlen(player->ini.gst_param[i]) > 0) {
4823 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4828 /* we would not do fork for scanning plugins */
4829 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4832 /* check disable registry scan */
4833 if (player->ini.skip_rescan) {
4834 argv[*argc] = g_strdup("--gst-disable-registry-update");
4838 /* check disable segtrap */
4839 if (player->ini.disable_segtrap) {
4840 argv[*argc] = g_strdup("--gst-disable-segtrap");
4844 LOGD("initializing gstreamer with following parameter");
4845 LOGD("argc : %d", *argc);
4848 for (i = 0; i < arg_count; i++) {
4850 LOGD("argv[%d] : %s", i, argv2[i]);
4853 /* initializing gstreamer */
4854 if (!gst_init_check(argc, &argv, &err)) {
4855 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4862 for (i = 0; i < arg_count; i++) {
4863 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4864 MMPLAYER_FREEIF(argv2[i]);
4867 MMPLAYER_FREEIF(argv);
4868 MMPLAYER_FREEIF(argv2);
4869 MMPLAYER_FREEIF(argc);
4879 for (i = 0; i < arg_count; i++) {
4880 LOGD("free[%d] : %s", i, argv2[i]);
4881 MMPLAYER_FREEIF(argv2[i]);
4884 MMPLAYER_FREEIF(argv);
4885 MMPLAYER_FREEIF(argv2);
4886 MMPLAYER_FREEIF(argc);
4892 __mmplayer_check_async_state_transition(mmplayer_t *player)
4894 GstState element_state = GST_STATE_VOID_PENDING;
4895 GstState element_pending_state = GST_STATE_VOID_PENDING;
4896 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4897 GstElement *element = NULL;
4898 gboolean async = FALSE;
4900 /* check player handle */
4901 MMPLAYER_RETURN_IF_FAIL(player &&
4903 player->pipeline->mainbin &&
4904 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4907 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4909 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4910 LOGD("don't need to check the pipeline state");
4914 MMPLAYER_PRINT_STATE(player);
4916 /* wait for state transition */
4917 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4918 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4920 if (ret == GST_STATE_CHANGE_FAILURE) {
4921 LOGE(" [%s] state : %s pending : %s",
4922 GST_ELEMENT_NAME(element),
4923 gst_element_state_get_name(element_state),
4924 gst_element_state_get_name(element_pending_state));
4926 /* dump state of all element */
4927 _mmplayer_dump_pipeline_state(player);
4932 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4937 _mmplayer_destroy(MMHandleType handle)
4939 mmplayer_t *player = MM_PLAYER_CAST(handle);
4943 /* check player handle */
4944 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4946 /* destroy can called at anytime */
4947 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4949 /* check async state transition */
4950 __mmplayer_check_async_state_transition(player);
4952 /* release gapless play thread */
4953 if (player->gapless_play_thread) {
4954 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4955 player->gapless_play_thread_exit = TRUE;
4956 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4957 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4959 LOGD("waitting for gapless play thread exit");
4960 g_thread_join(player->gapless_play_thread);
4961 g_mutex_clear(&player->gapless_play_thread_mutex);
4962 g_cond_clear(&player->gapless_play_thread_cond);
4963 LOGD("gapless play thread released");
4966 _mmplayer_release_video_capture(player);
4968 /* de-initialize resource manager */
4969 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4970 player->resource_manager))
4971 LOGE("failed to deinitialize resource manager");
4973 /* release pipeline */
4974 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4975 LOGE("failed to destory pipeline");
4976 return MM_ERROR_PLAYER_INTERNAL;
4979 g_queue_free(player->bus_msg_q);
4981 /* release subtitle info lock and cond */
4982 g_mutex_clear(&player->subtitle_info_mutex);
4983 g_cond_clear(&player->subtitle_info_cond);
4985 __mmplayer_release_dump_list(player->dump_list);
4987 /* release miscellaneous information */
4988 __mmplayer_release_misc(player);
4990 /* release miscellaneous information.
4991 these info needs to be released after pipeline is destroyed. */
4992 __mmplayer_release_misc_post(player);
4994 /* release attributes */
4995 _mmplayer_deconstruct_attribute(handle);
4998 g_mutex_clear(&player->fsink_lock);
5001 g_mutex_clear(&player->update_tag_lock);
5003 /* release video bo lock and cond */
5004 g_mutex_clear(&player->video_bo_mutex);
5005 g_cond_clear(&player->video_bo_cond);
5007 /* release media stream callback lock */
5008 g_mutex_clear(&player->media_stream_cb_lock);
5012 return MM_ERROR_NONE;
5016 _mmplayer_realize(MMHandleType hplayer)
5018 mmplayer_t *player = (mmplayer_t *)hplayer;
5021 MMHandleType attrs = 0;
5022 int ret = MM_ERROR_NONE;
5026 /* check player handle */
5027 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5029 /* check current state */
5030 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5032 attrs = MMPLAYER_GET_ATTRS(player);
5034 LOGE("fail to get attributes.");
5035 return MM_ERROR_PLAYER_INTERNAL;
5037 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5038 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5040 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5041 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5043 if (ret != MM_ERROR_NONE) {
5044 LOGE("failed to parse profile");
5049 if (uri && (strstr(uri, "es_buff://"))) {
5050 if (strstr(uri, "es_buff://push_mode"))
5051 player->es_player_push_mode = TRUE;
5053 player->es_player_push_mode = FALSE;
5056 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5057 LOGW("mms protocol is not supported format.");
5058 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5061 if (MMPLAYER_IS_STREAMING(player))
5062 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5064 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5066 player->smooth_streaming = FALSE;
5067 player->videodec_linked = 0;
5068 player->audiodec_linked = 0;
5069 player->textsink_linked = 0;
5070 player->is_external_subtitle_present = FALSE;
5071 player->is_external_subtitle_added_now = FALSE;
5072 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5073 player->video360_metadata.is_spherical = -1;
5074 player->is_openal_plugin_used = FALSE;
5075 player->demux_pad_index = 0;
5076 player->subtitle_language_list = NULL;
5077 player->is_subtitle_force_drop = FALSE;
5079 _mmplayer_track_initialize(player);
5080 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5082 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5083 gint prebuffer_ms = 0, rebuffer_ms = 0;
5085 player->streamer = _mm_player_streaming_create();
5086 _mm_player_streaming_initialize(player->streamer, TRUE);
5088 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5089 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5091 if (prebuffer_ms > 0) {
5092 prebuffer_ms = MAX(prebuffer_ms, 1000);
5093 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5096 if (rebuffer_ms > 0) {
5097 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5098 rebuffer_ms = MAX(rebuffer_ms, 1000);
5099 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5102 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5103 player->streamer->buffering_req.rebuffer_time);
5106 /* realize pipeline */
5107 ret = __mmplayer_gst_realize(player);
5108 if (ret != MM_ERROR_NONE)
5109 LOGE("fail to realize the player.");
5111 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5119 _mmplayer_unrealize(MMHandleType hplayer)
5121 mmplayer_t *player = (mmplayer_t *)hplayer;
5122 int ret = MM_ERROR_NONE;
5126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5128 MMPLAYER_CMD_UNLOCK(player);
5129 /* destroy the gst bus msg thread which is created during realize.
5130 this funct have to be called before getting cmd lock. */
5131 _mmplayer_bus_msg_thread_destroy(player);
5132 MMPLAYER_CMD_LOCK(player);
5134 /* check current state */
5135 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5137 /* check async state transition */
5138 __mmplayer_check_async_state_transition(player);
5140 /* unrealize pipeline */
5141 ret = __mmplayer_gst_unrealize(player);
5143 /* set asm stop if success */
5144 if (MM_ERROR_NONE == ret) {
5145 if (!player->interrupted_by_resource) {
5146 if (player->video_decoder_resource != NULL) {
5147 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5148 player->video_decoder_resource);
5149 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5150 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
5152 player->video_decoder_resource = NULL;
5155 if (player->video_overlay_resource != NULL) {
5156 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5157 player->video_overlay_resource);
5158 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5159 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
5161 player->video_overlay_resource = NULL;
5164 ret = mm_resource_manager_commit(player->resource_manager);
5165 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5166 LOGE("failed to commit resource releases, ret(0x%x)", ret);
5169 LOGE("failed and don't change asm state to stop");
5177 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5179 mmplayer_t *player = (mmplayer_t *)hplayer;
5181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5183 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5187 _mmplayer_get_state(MMHandleType hplayer, int *state)
5189 mmplayer_t *player = (mmplayer_t *)hplayer;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5193 *state = MMPLAYER_CURRENT_STATE(player);
5195 return MM_ERROR_NONE;
5199 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5201 GstElement *vol_element = NULL;
5202 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5208 /* check pipeline handle */
5209 if (!player->pipeline || !player->pipeline->audiobin) {
5210 LOGD("'%s' will be applied when audiobin is created", prop_name);
5212 /* NOTE : stored value will be used in create_audiobin
5213 * returning MM_ERROR_NONE here makes application to able to
5214 * set audio volume or mute at anytime.
5216 return MM_ERROR_NONE;
5219 if (player->build_audio_offload) {
5220 LOGD("offload pipeline");
5221 volume_elem_id = MMPLAYER_A_SINK;
5224 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5226 LOGE("failed to get vol element %d", volume_elem_id);
5227 return MM_ERROR_PLAYER_INTERNAL;
5230 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5232 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5233 LOGE("there is no '%s' property", prop_name);
5234 return MM_ERROR_PLAYER_INTERNAL;
5237 if (!strcmp(prop_name, "volume")) {
5238 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5239 } else if (!strcmp(prop_name, "mute")) {
5240 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5242 LOGE("invalid property %s", prop_name);
5243 return MM_ERROR_PLAYER_INTERNAL;
5246 return MM_ERROR_NONE;
5250 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5252 int ret = MM_ERROR_NONE;
5253 mmplayer_t *player = (mmplayer_t *)hplayer;
5256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5258 LOGD("volume = %f", volume);
5260 /* invalid factor range or not */
5261 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5262 LOGE("Invalid volume value");
5263 return MM_ERROR_INVALID_ARGUMENT;
5266 player->sound.volume = volume;
5268 ret = __mmplayer_gst_set_volume_property(player, "volume");
5275 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5277 mmplayer_t *player = (mmplayer_t *)hplayer;
5281 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5284 *volume = player->sound.volume;
5286 LOGD("current vol = %f", *volume);
5289 return MM_ERROR_NONE;
5293 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5295 int ret = MM_ERROR_NONE;
5296 mmplayer_t *player = (mmplayer_t *)hplayer;
5299 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5301 LOGD("mute = %d", mute);
5303 player->sound.mute = mute;
5305 ret = __mmplayer_gst_set_volume_property(player, "mute");
5312 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5314 mmplayer_t *player = (mmplayer_t *)hplayer;
5318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5319 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5321 *mute = player->sound.mute;
5323 LOGD("current mute = %d", *mute);
5327 return MM_ERROR_NONE;
5331 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5333 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5339 player->video_stream_changed_cb = callback;
5340 player->video_stream_changed_cb_user_param = user_param;
5341 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5345 return MM_ERROR_NONE;
5349 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5351 mmplayer_t *player = (mmplayer_t *)hplayer;
5355 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5357 player->audio_stream_changed_cb = callback;
5358 player->audio_stream_changed_cb_user_param = user_param;
5359 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5363 return MM_ERROR_NONE;
5367 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5369 mmplayer_t *player = (mmplayer_t *)hplayer;
5373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5375 player->audio_decoded_cb = callback;
5376 player->audio_decoded_cb_user_param = user_param;
5377 player->audio_extract_opt = opt;
5378 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5382 return MM_ERROR_NONE;
5386 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5388 mmplayer_t *player = (mmplayer_t *)hplayer;
5392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5394 if (callback && !player->bufmgr)
5395 player->bufmgr = tbm_bufmgr_init(-1);
5397 player->set_mode.video_export = (callback) ? true : false;
5398 player->video_decoded_cb = callback;
5399 player->video_decoded_cb_user_param = user_param;
5401 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5405 return MM_ERROR_NONE;
5409 _mmplayer_start(MMHandleType hplayer)
5411 mmplayer_t *player = (mmplayer_t *)hplayer;
5412 gint ret = MM_ERROR_NONE;
5416 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5418 /* check current state */
5419 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5421 /* start pipeline */
5422 ret = _mmplayer_gst_start(player);
5423 if (ret != MM_ERROR_NONE)
5424 LOGE("failed to start player.");
5426 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5427 LOGD("force playing start even during buffering");
5428 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5436 /* NOTE: post "not supported codec message" to application
5437 * when one codec is not found during AUTOPLUGGING in MSL.
5438 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5439 * And, if any codec is not found, don't send message here.
5440 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5443 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5445 MMMessageParamType msg_param;
5446 memset(&msg_param, 0, sizeof(MMMessageParamType));
5447 gboolean post_msg_direct = FALSE;
5451 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5453 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5454 player->not_supported_codec, player->can_support_codec);
5456 if (player->not_found_demuxer) {
5457 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5458 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5460 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5461 MMPLAYER_FREEIF(msg_param.data);
5463 return MM_ERROR_NONE;
5466 if (player->not_supported_codec) {
5467 if (player->can_support_codec) {
5468 // There is one codec to play
5469 post_msg_direct = TRUE;
5471 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5472 post_msg_direct = TRUE;
5475 if (post_msg_direct) {
5476 MMMessageParamType msg_param;
5477 memset(&msg_param, 0, sizeof(MMMessageParamType));
5479 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5480 LOGW("not found AUDIO codec, posting error code to application.");
5482 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5483 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5484 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5485 LOGW("not found VIDEO codec, posting error code to application.");
5487 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5488 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5491 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5493 MMPLAYER_FREEIF(msg_param.data);
5495 return MM_ERROR_NONE;
5497 // no any supported codec case
5498 LOGW("not found any codec, posting error code to application.");
5500 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5501 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5502 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5504 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5505 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5508 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5510 MMPLAYER_FREEIF(msg_param.data);
5516 return MM_ERROR_NONE;
5520 __mmplayer_check_pipeline(mmplayer_t *player)
5522 GstState element_state = GST_STATE_VOID_PENDING;
5523 GstState element_pending_state = GST_STATE_VOID_PENDING;
5525 int ret = MM_ERROR_NONE;
5527 if (!player->gapless.reconfigure)
5530 LOGW("pipeline is under construction.");
5532 MMPLAYER_PLAYBACK_LOCK(player);
5533 MMPLAYER_PLAYBACK_UNLOCK(player);
5535 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5537 /* wait for state transition */
5538 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5539 if (ret == GST_STATE_CHANGE_FAILURE)
5540 LOGE("failed to change pipeline state within %d sec", timeout);
5543 /* NOTE : it should be able to call 'stop' anytime*/
5545 _mmplayer_stop(MMHandleType hplayer)
5547 mmplayer_t *player = (mmplayer_t *)hplayer;
5548 int ret = MM_ERROR_NONE;
5552 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5554 /* check current state */
5555 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5557 /* check pipline building state */
5558 __mmplayer_check_pipeline(player);
5559 __mmplayer_reset_gapless_state(player);
5561 /* NOTE : application should not wait for EOS after calling STOP */
5562 _mmplayer_cancel_eos_timer(player);
5565 player->seek_state = MMPLAYER_SEEK_NONE;
5568 ret = _mmplayer_gst_stop(player);
5570 if (ret != MM_ERROR_NONE)
5571 LOGE("failed to stop player.");
5579 _mmplayer_pause(MMHandleType hplayer)
5581 mmplayer_t *player = (mmplayer_t *)hplayer;
5582 gint64 pos_nsec = 0;
5583 gboolean async = FALSE;
5584 gint ret = MM_ERROR_NONE;
5588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5590 /* check current state */
5591 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5593 /* check pipline building state */
5594 __mmplayer_check_pipeline(player);
5596 switch (MMPLAYER_CURRENT_STATE(player)) {
5597 case MM_PLAYER_STATE_READY:
5599 /* check prepare async or not.
5600 * In the case of streaming playback, it's recommned to avoid blocking wait.
5602 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5603 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5605 /* Changing back sync of rtspsrc to async */
5606 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5607 LOGD("async prepare working mode for rtsp");
5613 case MM_PLAYER_STATE_PLAYING:
5615 /* NOTE : store current point to overcome some bad operation
5616 *(returning zero when getting current position in paused state) of some
5619 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5620 LOGW("getting current position failed in paused");
5622 player->last_position = pos_nsec;
5624 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5625 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5626 This causes problem is position calculation during normal pause resume scenarios also.
5627 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5628 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5629 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5630 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5636 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5637 LOGD("doing async pause in case of ms buff src");
5641 /* pause pipeline */
5642 ret = _mmplayer_gst_pause(player, async);
5644 if (ret != MM_ERROR_NONE)
5645 LOGE("failed to pause player. ret : 0x%x", ret);
5647 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5648 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5649 LOGE("failed to update display_rotation");
5657 /* in case of streaming, pause could take long time.*/
5659 _mmplayer_abort_pause(MMHandleType hplayer)
5661 mmplayer_t *player = (mmplayer_t *)hplayer;
5662 int ret = MM_ERROR_NONE;
5666 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5668 player->pipeline->mainbin,
5669 MM_ERROR_PLAYER_NOT_INITIALIZED);
5671 LOGD("set the pipeline state to READY");
5673 /* set state to READY */
5674 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5675 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5676 if (ret != MM_ERROR_NONE) {
5677 LOGE("fail to change state to READY");
5678 return MM_ERROR_PLAYER_INTERNAL;
5681 LOGD("succeeded in changing state to READY");
5686 _mmplayer_resume(MMHandleType hplayer)
5688 mmplayer_t *player = (mmplayer_t *)hplayer;
5689 int ret = MM_ERROR_NONE;
5690 gboolean async = FALSE;
5694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5696 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5697 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5698 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5702 /* Changing back sync mode rtspsrc to async */
5703 LOGD("async resume for rtsp case");
5707 /* check current state */
5708 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5710 ret = _mmplayer_gst_resume(player, async);
5711 if (ret != MM_ERROR_NONE)
5712 LOGE("failed to resume player.");
5714 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5715 LOGD("force resume even during buffering");
5716 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5725 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5727 mmplayer_t *player = (mmplayer_t *)hplayer;
5728 gint64 pos_nsec = 0;
5729 int ret = MM_ERROR_NONE;
5731 signed long long start = 0, stop = 0;
5732 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5735 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5736 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5738 /* The sound of video is not supported under 0.0 and over 2.0. */
5739 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5740 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5743 _mmplayer_set_mute(hplayer, mute);
5745 if (player->playback_rate == rate)
5746 return MM_ERROR_NONE;
5748 /* If the position is reached at start potion during fast backward, EOS is posted.
5749 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5751 player->playback_rate = rate;
5753 current_state = MMPLAYER_CURRENT_STATE(player);
5755 if (current_state != MM_PLAYER_STATE_PAUSED)
5756 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5758 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5760 if ((current_state == MM_PLAYER_STATE_PAUSED)
5761 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5762 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5763 pos_nsec = player->last_position;
5768 stop = GST_CLOCK_TIME_NONE;
5770 start = GST_CLOCK_TIME_NONE;
5774 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5775 player->playback_rate,
5777 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5778 GST_SEEK_TYPE_SET, start,
5779 GST_SEEK_TYPE_SET, stop)) {
5780 LOGE("failed to set speed playback");
5781 return MM_ERROR_PLAYER_SEEK;
5784 LOGD("succeeded to set speed playback as %0.1f", rate);
5788 return MM_ERROR_NONE;;
5792 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5794 mmplayer_t *player = (mmplayer_t *)hplayer;
5795 int ret = MM_ERROR_NONE;
5799 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5801 /* check pipline building state */
5802 __mmplayer_check_pipeline(player);
5804 ret = _mmplayer_gst_set_position(player, position, FALSE);
5812 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5814 mmplayer_t *player = (mmplayer_t *)hplayer;
5815 int ret = MM_ERROR_NONE;
5817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5818 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5820 if (g_strrstr(player->type, "video/mpegts"))
5821 __mmplayer_update_duration_value(player);
5823 *duration = player->duration;
5828 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5830 mmplayer_t *player = (mmplayer_t *)hplayer;
5831 int ret = MM_ERROR_NONE;
5833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5835 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5841 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5843 mmplayer_t *player = (mmplayer_t *)hplayer;
5844 int ret = MM_ERROR_NONE;
5848 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5850 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5858 __mmplayer_is_midi_type(gchar *str_caps)
5860 if ((g_strrstr(str_caps, "audio/midi")) ||
5861 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5862 (g_strrstr(str_caps, "application/x-smaf")) ||
5863 (g_strrstr(str_caps, "audio/x-imelody")) ||
5864 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5865 (g_strrstr(str_caps, "audio/xmf")) ||
5866 (g_strrstr(str_caps, "audio/mxmf"))) {
5875 __mmplayer_is_only_mp3_type(gchar *str_caps)
5877 if (g_strrstr(str_caps, "application/x-id3") ||
5878 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5884 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5886 GstStructure *caps_structure = NULL;
5887 gint samplerate = 0;
5891 MMPLAYER_RETURN_IF_FAIL(player && caps);
5893 caps_structure = gst_caps_get_structure(caps, 0);
5895 /* set stream information */
5896 gst_structure_get_int(caps_structure, "rate", &samplerate);
5897 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5899 gst_structure_get_int(caps_structure, "channels", &channels);
5900 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5902 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5906 __mmplayer_update_content_type_info(mmplayer_t *player)
5909 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5911 if (__mmplayer_is_midi_type(player->type)) {
5912 player->bypass_audio_effect = TRUE;
5916 if (!player->streamer) {
5917 LOGD("no need to check streaming type");
5921 if (g_strrstr(player->type, "application/x-hls")) {
5922 /* If it can't know exact type when it parses uri because of redirection case,
5923 * it will be fixed by typefinder or when doing autoplugging.
5925 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5926 player->streamer->is_adaptive_streaming = TRUE;
5927 } else if (g_strrstr(player->type, "application/dash+xml")) {
5928 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5929 player->streamer->is_adaptive_streaming = TRUE;
5932 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5933 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5934 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5936 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5937 if (player->streamer->is_adaptive_streaming)
5938 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5940 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5944 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5949 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5950 GstCaps *caps, gpointer data)
5952 mmplayer_t *player = (mmplayer_t *)data;
5957 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5959 /* store type string */
5960 MMPLAYER_FREEIF(player->type);
5961 player->type = gst_caps_to_string(caps);
5963 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5964 player, player->type, probability, gst_caps_get_size(caps));
5966 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5967 (g_strrstr(player->type, "audio/x-raw-int"))) {
5968 LOGE("not support media format");
5970 if (player->msg_posted == FALSE) {
5971 MMMessageParamType msg_param;
5972 memset(&msg_param, 0, sizeof(MMMessageParamType));
5974 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5975 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5977 /* don't post more if one was sent already */
5978 player->msg_posted = TRUE;
5983 __mmplayer_update_content_type_info(player);
5985 pad = gst_element_get_static_pad(tf, "src");
5987 LOGE("fail to get typefind src pad.");
5991 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5992 gboolean async = FALSE;
5993 LOGE("failed to autoplug %s", player->type);
5995 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5997 if (async && player->msg_posted == FALSE)
5998 __mmplayer_handle_missed_plugin(player);
6002 gst_object_unref(GST_OBJECT(pad));
6010 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6012 GstElement *decodebin = NULL;
6016 /* create decodebin */
6017 decodebin = gst_element_factory_make("decodebin", NULL);
6020 LOGE("fail to create decodebin");
6024 /* raw pad handling signal */
6025 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6026 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6028 /* no-more-pad pad handling signal */
6029 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6030 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6032 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6033 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6035 /* This signal is emitted when a pad for which there is no further possible
6036 decoding is added to the decodebin.*/
6037 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6038 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6040 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6041 before looking for any elements that can handle that stream.*/
6042 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6043 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6045 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6046 before looking for any elements that can handle that stream.*/
6047 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6048 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6050 /* This signal is emitted once decodebin has finished decoding all the data.*/
6051 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6052 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6054 /* This signal is emitted when a element is added to the bin.*/
6055 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6056 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6063 __mmplayer_gst_make_queue2(mmplayer_t *player)
6065 GstElement *queue2 = NULL;
6066 gint64 dur_bytes = 0L;
6067 mmplayer_gst_element_t *mainbin = NULL;
6068 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6071 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6073 mainbin = player->pipeline->mainbin;
6075 queue2 = gst_element_factory_make("queue2", "queue2");
6077 LOGE("failed to create buffering queue element");
6081 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6082 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6084 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6086 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6087 * skip the pull mode(file or ring buffering) setting. */
6088 if (dur_bytes > 0) {
6089 if (!g_strrstr(player->type, "video/mpegts")) {
6090 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6091 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6097 _mm_player_streaming_set_queue2(player->streamer,
6101 (guint64)dur_bytes); /* no meaning at the moment */
6107 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6109 mmplayer_gst_element_t *mainbin = NULL;
6110 GstElement *decodebin = NULL;
6111 GstElement *queue2 = NULL;
6112 GstPad *sinkpad = NULL;
6113 GstPad *qsrcpad = NULL;
6116 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6118 mainbin = player->pipeline->mainbin;
6120 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6122 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6123 LOGW("need to check: muxed buffer is not null");
6126 queue2 = __mmplayer_gst_make_queue2(player);
6128 LOGE("failed to make queue2");
6132 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6133 LOGE("failed to add buffering queue");
6137 sinkpad = gst_element_get_static_pad(queue2, "sink");
6138 qsrcpad = gst_element_get_static_pad(queue2, "src");
6140 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6141 LOGE("failed to link [%s:%s]-[%s:%s]",
6142 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6146 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6147 LOGE("failed to sync queue2 state with parent");
6151 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6152 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6156 gst_object_unref(GST_OBJECT(sinkpad));
6160 /* create decodebin */
6161 decodebin = _mmplayer_gst_make_decodebin(player);
6163 LOGE("failed to make decodebin");
6167 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6168 LOGE("failed to add decodebin");
6172 /* to force caps on the decodebin element and avoid reparsing stuff by
6173 * typefind. It also avoids a deadlock in the way typefind activates pads in
6174 * the state change */
6175 g_object_set(decodebin, "sink-caps", caps, NULL);
6177 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6179 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6180 LOGE("failed to link [%s:%s]-[%s:%s]",
6181 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6185 gst_object_unref(GST_OBJECT(sinkpad));
6187 gst_object_unref(GST_OBJECT(qsrcpad));
6190 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6191 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6193 /* set decodebin property about buffer in streaming playback. *
6194 * in case of HLS/DASH, it does not need to have big buffer *
6195 * because it is kind of adaptive streaming. */
6196 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6197 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6198 gint high_percent = 0;
6200 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6201 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6203 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6205 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6207 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6208 "high-percent", high_percent,
6209 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6210 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6211 "max-size-buffers", 0, NULL); // disable or automatic
6214 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6215 LOGE("failed to sync decodebin state with parent");
6226 gst_object_unref(GST_OBJECT(sinkpad));
6229 gst_object_unref(GST_OBJECT(qsrcpad));
6232 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6233 * You need to explicitly set elements to the NULL state before
6234 * dropping the final reference, to allow them to clean up.
6236 gst_element_set_state(queue2, GST_STATE_NULL);
6238 /* And, it still has a parent "player".
6239 * You need to let the parent manage the object instead of unreffing the object directly.
6241 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6242 gst_object_unref(queue2);
6247 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6248 * You need to explicitly set elements to the NULL state before
6249 * dropping the final reference, to allow them to clean up.
6251 gst_element_set_state(decodebin, GST_STATE_NULL);
6253 /* And, it still has a parent "player".
6254 * You need to let the parent manage the object instead of unreffing the object directly.
6257 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6258 gst_object_unref(decodebin);
6266 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6270 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6271 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6273 LOGD("class : %s, mime : %s", factory_class, mime);
6275 /* add missing plugin */
6276 /* NOTE : msl should check missing plugin for image mime type.
6277 * Some motion jpeg clips can have playable audio track.
6278 * So, msl have to play audio after displaying popup written video format not supported.
6280 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6281 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6282 LOGD("not found demuxer");
6283 player->not_found_demuxer = TRUE;
6284 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6290 if (!g_strrstr(factory_class, "Demuxer")) {
6291 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6292 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6293 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6295 /* check that clip have multi tracks or not */
6296 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6297 LOGD("video plugin is already linked");
6299 LOGW("add VIDEO to missing plugin");
6300 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6301 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6303 } else if (g_str_has_prefix(mime, "audio")) {
6304 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6305 LOGD("audio plugin is already linked");
6307 LOGW("add AUDIO to missing plugin");
6308 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6309 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6317 return MM_ERROR_NONE;
6321 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6323 mmplayer_t *player = (mmplayer_t *)data;
6327 MMPLAYER_RETURN_IF_FAIL(player);
6329 /* remove fakesink. */
6330 if (!_mmplayer_gst_remove_fakesink(player,
6331 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6332 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6333 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6334 * source element are not same. To overcome this situation, this function will called
6335 * several places and several times. Therefore, this is not an error case.
6340 LOGD("[handle: %p] pipeline has completely constructed", player);
6342 if ((player->ini.async_start) &&
6343 (player->msg_posted == FALSE) &&
6344 (player->cmd >= MMPLAYER_COMMAND_START))
6345 __mmplayer_handle_missed_plugin(player);
6347 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6351 __mmplayer_check_profile(void)
6354 static int profile_tv = -1;
6356 if (__builtin_expect(profile_tv != -1, 1))
6359 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6360 switch (*profileName) {
6375 __mmplayer_get_next_uri(mmplayer_t *player)
6377 mmplayer_parse_profile_t profile;
6379 guint num_of_list = 0;
6382 num_of_list = g_list_length(player->uri_info.uri_list);
6383 uri_idx = player->uri_info.uri_idx;
6385 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6386 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6387 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6389 LOGW("next uri does not exist");
6393 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6394 LOGE("failed to parse profile");
6398 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6399 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6400 LOGW("uri type is not supported(%d)", profile.uri_type);
6404 LOGD("success to find next uri %d", uri_idx);
6408 if (uri_idx == num_of_list) {
6409 LOGE("failed to find next uri");
6413 player->uri_info.uri_idx = uri_idx;
6414 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6416 if (mm_attrs_commit_all(player->attrs)) {
6417 LOGE("failed to commit");
6421 SECURE_LOGD("next playback uri: %s", uri);
6426 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6428 #define REPEAT_COUNT_INFINITE -1
6429 #define REPEAT_COUNT_MIN 2
6430 #define ORIGINAL_URI_ONLY 1
6432 MMHandleType attrs = 0;
6436 guint num_of_uri = 0;
6437 int profile_tv = -1;
6441 LOGD("checking for gapless play option");
6443 if (player->pipeline->textbin) {
6444 LOGE("subtitle path is enabled. gapless play is not supported.");
6448 attrs = MMPLAYER_GET_ATTRS(player);
6450 LOGE("fail to get attributes.");
6454 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6456 /* gapless playback is not supported in case of video at TV profile. */
6457 profile_tv = __mmplayer_check_profile();
6458 if (profile_tv && video) {
6459 LOGW("not support video gapless playback");
6463 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6464 LOGE("failed to get play count");
6466 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6467 LOGE("failed to get gapless mode");
6469 /* check repeat count in case of audio */
6471 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6472 LOGW("gapless is disabled");
6476 num_of_uri = g_list_length(player->uri_info.uri_list);
6478 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6480 if (num_of_uri == ORIGINAL_URI_ONLY) {
6481 /* audio looping path */
6482 if (count >= REPEAT_COUNT_MIN) {
6483 /* decrease play count */
6484 /* we succeeded to rewind. update play count and then wait for next EOS */
6486 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6487 /* commit attribute */
6488 if (mm_attrs_commit_all(attrs))
6489 LOGE("failed to commit attribute");
6491 } else if (count != REPEAT_COUNT_INFINITE) {
6492 LOGD("there is no next uri and no repeat");
6495 LOGD("looping cnt %d", count);
6497 /* gapless playback path */
6498 if (!__mmplayer_get_next_uri(player)) {
6499 LOGE("failed to get next uri");
6506 LOGE("unable to play gapless path. EOS will be posted soon");
6511 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6513 mmplayer_selector_t *selector = &player->selector[type];
6514 mmplayer_gst_element_t *sinkbin = NULL;
6515 main_element_id_e selectorId = MMPLAYER_M_NUM;
6516 main_element_id_e sinkId = MMPLAYER_M_NUM;
6517 GstPad *srcpad = NULL;
6518 GstPad *sinkpad = NULL;
6519 gboolean send_notice = FALSE;
6522 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6524 LOGD("type %d", type);
6527 case MM_PLAYER_TRACK_TYPE_AUDIO:
6528 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6529 sinkId = MMPLAYER_A_BIN;
6530 sinkbin = player->pipeline->audiobin;
6532 case MM_PLAYER_TRACK_TYPE_VIDEO:
6533 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6534 sinkId = MMPLAYER_V_BIN;
6535 sinkbin = player->pipeline->videobin;
6538 case MM_PLAYER_TRACK_TYPE_TEXT:
6539 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6540 sinkId = MMPLAYER_T_BIN;
6541 sinkbin = player->pipeline->textbin;
6544 LOGE("requested type is not supportable");
6549 if (player->pipeline->mainbin[selectorId].gst) {
6552 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6554 if (selector->event_probe_id != 0)
6555 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6556 selector->event_probe_id = 0;
6558 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6559 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6561 if (srcpad && sinkpad) {
6562 /* after getting drained signal there is no data flows, so no need to do pad_block */
6563 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6564 gst_pad_unlink(srcpad, sinkpad);
6566 /* send custom event to sink pad to handle it at video sink */
6568 LOGD("send custom event to sinkpad");
6569 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6570 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6571 gst_pad_send_event(sinkpad, event);
6575 gst_object_unref(sinkpad);
6578 gst_object_unref(srcpad);
6581 LOGD("selector release");
6583 /* release and unref requests pad from the selector */
6584 for (n = 0; n < selector->channels->len; n++) {
6585 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6586 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6588 g_ptr_array_set_size(selector->channels, 0);
6590 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6591 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6593 player->pipeline->mainbin[selectorId].gst = NULL;
6601 __mmplayer_deactivate_old_path(mmplayer_t *player)
6604 MMPLAYER_RETURN_IF_FAIL(player);
6606 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6607 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6608 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6609 LOGE("deactivate selector error");
6613 _mmplayer_track_destroy(player);
6614 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6616 if (player->streamer) {
6617 _mm_player_streaming_initialize(player->streamer, FALSE);
6618 _mm_player_streaming_destroy(player->streamer);
6619 player->streamer = NULL;
6622 MMPLAYER_PLAYBACK_LOCK(player);
6623 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6630 if (!player->msg_posted) {
6631 MMMessageParamType msg = {0,};
6634 msg.code = MM_ERROR_PLAYER_INTERNAL;
6635 LOGE("gapless_uri_play> deactivate error");
6637 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6638 player->msg_posted = TRUE;
6644 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6646 int result = MM_ERROR_NONE;
6647 mmplayer_t *player = (mmplayer_t *)hplayer;
6650 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6652 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6653 if (mm_attrs_commit_all(player->attrs)) {
6654 LOGE("failed to commit the original uri.");
6655 result = MM_ERROR_PLAYER_INTERNAL;
6657 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6658 LOGE("failed to add the original uri in the uri list.");
6666 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6668 mmplayer_t *player = (mmplayer_t *)hplayer;
6669 guint num_of_list = 0;
6673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6674 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6676 if (player->pipeline && player->pipeline->textbin) {
6677 LOGE("subtitle path is enabled.");
6678 return MM_ERROR_PLAYER_INVALID_STATE;
6681 num_of_list = g_list_length(player->uri_info.uri_list);
6683 if (is_first_path) {
6684 if (num_of_list == 0) {
6685 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6686 SECURE_LOGD("add original path : %s", uri);
6688 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6689 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6691 SECURE_LOGD("change original path : %s", uri);
6694 MMHandleType attrs = 0;
6695 attrs = MMPLAYER_GET_ATTRS(player);
6697 if (num_of_list == 0) {
6698 char *original_uri = NULL;
6701 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6703 if (!original_uri) {
6704 LOGE("there is no original uri.");
6705 return MM_ERROR_PLAYER_INVALID_STATE;
6708 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6709 player->uri_info.uri_idx = 0;
6711 SECURE_LOGD("add original path at first : %s", original_uri);
6715 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6716 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6720 return MM_ERROR_NONE;
6724 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6726 mmplayer_t *player = (mmplayer_t *)hplayer;
6727 char *next_uri = NULL;
6728 guint num_of_list = 0;
6731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6733 num_of_list = g_list_length(player->uri_info.uri_list);
6735 if (num_of_list > 0) {
6736 gint uri_idx = player->uri_info.uri_idx;
6738 if (uri_idx < num_of_list-1)
6743 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6744 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6746 *uri = g_strdup(next_uri);
6750 return MM_ERROR_NONE;
6754 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6755 GstCaps *caps, gpointer data)
6757 mmplayer_t *player = (mmplayer_t *)data;
6758 const gchar *klass = NULL;
6759 const gchar *mime = NULL;
6760 gchar *caps_str = NULL;
6762 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6763 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6764 caps_str = gst_caps_to_string(caps);
6766 LOGW("unknown type of caps : %s from %s",
6767 caps_str, GST_ELEMENT_NAME(elem));
6769 MMPLAYER_FREEIF(caps_str);
6771 /* There is no available codec. */
6772 __mmplayer_check_not_supported_codec(player, klass, mime);
6776 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6777 GstCaps *caps, gpointer data)
6779 mmplayer_t *player = (mmplayer_t *)data;
6780 const char *mime = NULL;
6781 gboolean ret = TRUE;
6783 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6784 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6786 if (g_str_has_prefix(mime, "audio")) {
6787 GstStructure *caps_structure = NULL;
6788 gint samplerate = 0;
6790 gchar *caps_str = NULL;
6792 caps_structure = gst_caps_get_structure(caps, 0);
6793 gst_structure_get_int(caps_structure, "rate", &samplerate);
6794 gst_structure_get_int(caps_structure, "channels", &channels);
6796 if ((channels > 0 && samplerate == 0)) {
6797 LOGD("exclude audio...");
6801 caps_str = gst_caps_to_string(caps);
6802 /* set it directly because not sent by TAG */
6803 if (g_strrstr(caps_str, "mobile-xmf"))
6804 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6805 MMPLAYER_FREEIF(caps_str);
6806 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6807 MMMessageParamType msg_param;
6808 memset(&msg_param, 0, sizeof(MMMessageParamType));
6809 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6810 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6811 LOGD("video file is not supported on this device");
6813 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6814 LOGD("already video linked");
6817 LOGD("found new stream");
6824 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6826 gboolean ret = TRUE;
6827 GDBusConnection *conn = NULL;
6829 GVariant *result = NULL;
6830 const gchar *dbus_device_type = NULL;
6831 const gchar *dbus_ret = NULL;
6834 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6836 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6842 result = g_dbus_connection_call_sync(conn,
6843 "org.pulseaudio.Server",
6844 "/org/pulseaudio/StreamManager",
6845 "org.pulseaudio.StreamManager",
6846 "GetCurrentMediaRoutingPath",
6847 g_variant_new("(s)", "out"),
6848 G_VARIANT_TYPE("(ss)"),
6849 G_DBUS_CALL_FLAGS_NONE,
6853 if (!result || err) {
6854 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6860 /* device type is listed in stream-map.json at mmfw-sysconf */
6861 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6863 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6864 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6869 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6870 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6871 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6872 LOGD("audio offload is supportable");
6878 LOGD("audio offload is not supportable");
6882 g_variant_unref(result);
6883 g_object_unref(conn);
6888 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6890 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6891 gint64 position = 0;
6893 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6894 player->pipeline && player->pipeline->mainbin);
6896 MMPLAYER_CMD_LOCK(player);
6897 current_state = MMPLAYER_CURRENT_STATE(player);
6899 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6900 LOGW("getting current position failed in paused");
6902 _mmplayer_unrealize((MMHandleType)player);
6903 _mmplayer_realize((MMHandleType)player);
6905 _mmplayer_set_position((MMHandleType)player, position);
6907 /* async not to be blocked in streaming case */
6908 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6909 if (mm_attrs_commit_all(player->attrs))
6910 LOGE("failed to commit");
6912 _mmplayer_pause((MMHandleType)player);
6914 if (current_state == MM_PLAYER_STATE_PLAYING)
6915 _mmplayer_start((MMHandleType)player);
6916 MMPLAYER_CMD_UNLOCK(player);
6918 LOGD("rebuilding audio pipeline is completed.");
6921 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6923 mmplayer_t *player = (mmplayer_t *)user_data;
6924 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6925 gboolean is_supportable = FALSE;
6927 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6928 LOGW("failed to get device type");
6930 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6932 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6933 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6934 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6935 LOGD("ignore this dev connected info");
6939 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6940 if (player->build_audio_offload == is_supportable) {
6941 LOGD("keep current pipeline without re-building");
6945 /* rebuild pipeline */
6946 LOGD("re-build pipeline - offload: %d", is_supportable);
6947 player->build_audio_offload = FALSE;
6948 __mmplayer_rebuild_audio_pipeline(player);
6954 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6956 unsigned int id = 0;
6958 if (player->audio_device_cb_id != 0) {
6959 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6963 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6964 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6965 LOGD("added device connected cb (%u)", id);
6966 player->audio_device_cb_id = id;
6968 LOGW("failed to add device connected cb");
6976 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6978 gboolean ret = FALSE;
6979 GstElementFactory *factory = NULL;
6982 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6984 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6985 if (!__mmplayer_is_only_mp3_type(player->type))
6988 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6989 LOGD("there is no audio offload sink");
6993 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6994 LOGW("there is no audio device type to support offload");
6998 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7000 LOGW("there is no installed audio offload sink element");
7003 gst_object_unref(factory);
7005 if (!__mmplayer_add_audio_device_connected_cb(player))
7008 if (!__mmplayer_is_audio_offload_device_type(player))
7011 LOGD("audio offload can be built");
7019 static GstAutoplugSelectResult
7020 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7022 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7024 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7025 int audio_offload = 0;
7027 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7028 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7030 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7031 LOGD("expose audio path to build offload output path");
7032 player->build_audio_offload = TRUE;
7033 /* update codec info */
7034 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7035 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7036 player->audiodec_linked = 1;
7038 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7042 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7044 LOGD("audio codec type: %d", codec_type);
7045 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7046 /* sw codec will be skipped */
7047 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7048 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7049 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7050 ret = GST_AUTOPLUG_SELECT_SKIP;
7054 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7055 /* hw codec will be skipped */
7056 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7057 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7058 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7059 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 /* set stream information */
7065 if (!player->audiodec_linked)
7066 __mmplayer_set_audio_attrs(player, caps);
7068 /* update codec info */
7069 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7070 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7071 player->audiodec_linked = 1;
7073 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7075 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7077 LOGD("video codec type: %d", codec_type);
7078 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7079 /* sw codec is skipped */
7080 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7081 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7082 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7083 ret = GST_AUTOPLUG_SELECT_SKIP;
7087 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7088 /* hw codec is skipped */
7089 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7090 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7091 ret = GST_AUTOPLUG_SELECT_SKIP;
7096 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7097 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7099 /* mark video decoder for acquire */
7100 if (player->video_decoder_resource == NULL) {
7101 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7102 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7103 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7104 &player->video_decoder_resource)
7105 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7106 LOGE("could not mark video_decoder resource for acquire");
7107 ret = GST_AUTOPLUG_SELECT_SKIP;
7111 LOGW("video decoder resource is already acquired, skip it.");
7112 ret = GST_AUTOPLUG_SELECT_SKIP;
7116 player->interrupted_by_resource = FALSE;
7117 /* acquire resources for video playing */
7118 if (mm_resource_manager_commit(player->resource_manager)
7119 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7120 LOGE("could not acquire resources for video decoding");
7121 ret = GST_AUTOPLUG_SELECT_SKIP;
7126 /* update codec info */
7127 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7128 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7129 player->videodec_linked = 1;
7137 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7138 GstCaps *caps, GstElementFactory *factory, gpointer data)
7140 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7141 mmplayer_t *player = (mmplayer_t *)data;
7143 gchar *factory_name = NULL;
7144 gchar *caps_str = NULL;
7145 const gchar *klass = NULL;
7148 factory_name = GST_OBJECT_NAME(factory);
7149 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7150 caps_str = gst_caps_to_string(caps);
7152 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7154 /* store type string */
7155 if (player->type == NULL) {
7156 player->type = gst_caps_to_string(caps);
7157 __mmplayer_update_content_type_info(player);
7160 /* filtering exclude keyword */
7161 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7162 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7163 LOGW("skipping [%s] by exculde keyword [%s]",
7164 factory_name, player->ini.exclude_element_keyword[idx]);
7166 result = GST_AUTOPLUG_SELECT_SKIP;
7171 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7172 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7173 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7174 factory_name, player->ini.unsupported_codec_keyword[idx]);
7175 result = GST_AUTOPLUG_SELECT_SKIP;
7180 /* exclude webm format */
7181 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7182 * because webm format is not supportable.
7183 * If webm is disabled in "autoplug-continue", there is no state change
7184 * failure or error because the decodebin will expose the pad directly.
7185 * It make MSL invoke _prepare_async_callback.
7186 * So, we need to disable webm format in "autoplug-select" */
7187 if (caps_str && strstr(caps_str, "webm")) {
7188 LOGW("webm is not supported");
7189 result = GST_AUTOPLUG_SELECT_SKIP;
7193 /* check factory class for filtering */
7194 /* NOTE : msl don't need to use image plugins.
7195 * So, those plugins should be skipped for error handling.
7197 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7198 LOGD("skipping [%s] by not required", factory_name);
7199 result = GST_AUTOPLUG_SELECT_SKIP;
7203 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7204 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7205 // TO CHECK : subtitle if needed, add subparse exception.
7206 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7207 result = GST_AUTOPLUG_SELECT_SKIP;
7211 if (g_strrstr(factory_name, "mpegpsdemux")) {
7212 LOGD("skipping PS container - not support");
7213 result = GST_AUTOPLUG_SELECT_SKIP;
7217 if (g_strrstr(factory_name, "mssdemux"))
7218 player->smooth_streaming = TRUE;
7220 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7221 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7224 GstStructure *str = NULL;
7225 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7227 /* don't make video because of not required */
7228 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7229 (!player->set_mode.video_export)) {
7230 LOGD("no need video decoding, expose pad");
7231 result = GST_AUTOPLUG_SELECT_EXPOSE;
7235 /* get w/h for omx state-tune */
7236 /* FIXME: deprecated? */
7237 str = gst_caps_get_structure(caps, 0);
7238 gst_structure_get_int(str, "width", &width);
7241 if (player->v_stream_caps) {
7242 gst_caps_unref(player->v_stream_caps);
7243 player->v_stream_caps = NULL;
7246 player->v_stream_caps = gst_caps_copy(caps);
7247 LOGD("take caps for video state tune");
7248 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7252 if (g_strrstr(klass, "Codec/Decoder")) {
7253 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7254 if (result != GST_AUTOPLUG_SELECT_TRY) {
7255 LOGW("skip add decoder");
7261 MMPLAYER_FREEIF(caps_str);
7267 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7270 //mmplayer_t *player = (mmplayer_t *)data;
7271 GstCaps *caps = NULL;
7273 LOGD("[Decodebin2] pad-removed signal");
7275 caps = gst_pad_query_caps(new_pad, NULL);
7277 LOGW("query caps is NULL");
7281 gchar *caps_str = NULL;
7282 caps_str = gst_caps_to_string(caps);
7284 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7286 MMPLAYER_FREEIF(caps_str);
7287 gst_caps_unref(caps);
7291 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7293 mmplayer_t *player = (mmplayer_t *)data;
7294 GstIterator *iter = NULL;
7295 GValue item = { 0, };
7297 gboolean done = FALSE;
7298 gboolean is_all_drained = TRUE;
7301 MMPLAYER_RETURN_IF_FAIL(player);
7303 LOGD("__mmplayer_gst_decode_drained");
7305 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7306 LOGW("Fail to get cmd lock");
7310 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7311 !__mmplayer_verify_gapless_play_path(player)) {
7312 LOGD("decoding is finished.");
7313 __mmplayer_reset_gapless_state(player);
7314 MMPLAYER_CMD_UNLOCK(player);
7318 player->gapless.reconfigure = TRUE;
7320 /* check decodebin src pads whether they received EOS or not */
7321 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7324 switch (gst_iterator_next(iter, &item)) {
7325 case GST_ITERATOR_OK:
7326 pad = g_value_get_object(&item);
7327 if (pad && !GST_PAD_IS_EOS(pad)) {
7328 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7329 is_all_drained = FALSE;
7332 g_value_reset(&item);
7334 case GST_ITERATOR_RESYNC:
7335 gst_iterator_resync(iter);
7337 case GST_ITERATOR_ERROR:
7338 case GST_ITERATOR_DONE:
7343 g_value_unset(&item);
7344 gst_iterator_free(iter);
7346 if (!is_all_drained) {
7347 LOGD("Wait util the all pads get EOS.");
7348 MMPLAYER_CMD_UNLOCK(player);
7353 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7354 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7356 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7357 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7358 __mmplayer_deactivate_old_path(player);
7359 MMPLAYER_CMD_UNLOCK(player);
7365 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7367 mmplayer_t *player = (mmplayer_t *)data;
7368 const gchar *klass = NULL;
7369 gchar *factory_name = NULL;
7371 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7372 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7374 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7376 if (__mmplayer_add_dump_buffer_probe(player, element))
7377 LOGD("add buffer probe");
7379 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7380 gchar *selected = NULL;
7381 selected = g_strdup(GST_ELEMENT_NAME(element));
7382 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7385 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7386 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7387 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7389 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7390 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7392 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7393 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7394 "max-video-width", player->adaptive_info.limit.width,
7395 "max-video-height", player->adaptive_info.limit.height, NULL);
7397 } else if (g_strrstr(klass, "Demuxer")) {
7398 //LOGD("plugged element is demuxer. take it");
7399 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7400 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7403 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7404 int surface_type = 0;
7406 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7409 // to support trust-zone only
7410 if (g_strrstr(factory_name, "asfdemux")) {
7411 LOGD("set file-location %s", player->profile.uri);
7412 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7413 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7414 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7415 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7416 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7417 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7418 (__mmplayer_is_only_mp3_type(player->type))) {
7419 LOGD("[mpegaudioparse] set streaming pull mode.");
7420 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7422 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7423 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7426 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7427 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7428 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7430 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7431 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7433 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7434 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7435 (MMPLAYER_IS_DASH_STREAMING(player))) {
7436 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7437 _mm_player_streaming_set_multiqueue(player->streamer, element);
7438 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7447 __mmplayer_release_misc(mmplayer_t *player)
7450 bool cur_mode = player->set_mode.rich_audio;
7453 MMPLAYER_RETURN_IF_FAIL(player);
7455 player->video_decoded_cb = NULL;
7456 player->video_decoded_cb_user_param = NULL;
7457 player->video_stream_prerolled = false;
7459 player->audio_decoded_cb = NULL;
7460 player->audio_decoded_cb_user_param = NULL;
7461 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7463 player->video_stream_changed_cb = NULL;
7464 player->video_stream_changed_cb_user_param = NULL;
7466 player->audio_stream_changed_cb = NULL;
7467 player->audio_stream_changed_cb_user_param = NULL;
7469 player->sent_bos = FALSE;
7470 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7472 player->seek_state = MMPLAYER_SEEK_NONE;
7474 player->total_bitrate = 0;
7475 player->total_maximum_bitrate = 0;
7477 player->not_found_demuxer = 0;
7479 player->last_position = 0;
7480 player->duration = 0;
7481 player->http_content_size = 0;
7482 player->not_supported_codec = MISSING_PLUGIN_NONE;
7483 player->can_support_codec = FOUND_PLUGIN_NONE;
7484 player->pending_seek.is_pending = false;
7485 player->pending_seek.pos = 0;
7486 player->msg_posted = FALSE;
7487 player->has_many_types = FALSE;
7488 player->is_subtitle_force_drop = FALSE;
7489 player->play_subtitle = FALSE;
7490 player->adjust_subtitle_pos = 0;
7491 player->has_closed_caption = FALSE;
7492 player->set_mode.video_export = false;
7493 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7494 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7496 player->set_mode.rich_audio = cur_mode;
7498 if (player->audio_device_cb_id > 0 &&
7499 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7500 LOGW("failed to remove audio device_connected_callback");
7501 player->audio_device_cb_id = 0;
7503 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7504 player->bitrate[i] = 0;
7505 player->maximum_bitrate[i] = 0;
7508 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7510 /* remove media stream cb(appsrc cb) */
7511 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7512 player->media_stream_buffer_status_cb[i] = NULL;
7513 player->media_stream_seek_data_cb[i] = NULL;
7514 player->buffer_cb_user_param[i] = NULL;
7515 player->seek_cb_user_param[i] = NULL;
7517 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7519 /* free memory related to audio effect */
7520 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7522 if (player->adaptive_info.var_list) {
7523 g_list_free_full(player->adaptive_info.var_list, g_free);
7524 player->adaptive_info.var_list = NULL;
7527 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7528 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7529 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7531 /* Reset video360 settings to their defaults in case if the pipeline is to be
7534 player->video360_metadata.is_spherical = -1;
7535 player->is_openal_plugin_used = FALSE;
7537 player->is_content_spherical = FALSE;
7538 player->is_video360_enabled = TRUE;
7539 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7540 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7541 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7542 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7543 player->video360_zoom = 1.0f;
7544 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7545 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7547 player->sound.rg_enable = false;
7549 __mmplayer_initialize_video_roi(player);
7554 __mmplayer_release_misc_post(mmplayer_t *player)
7556 char *original_uri = NULL;
7559 /* player->pipeline is already released before. */
7561 MMPLAYER_RETURN_IF_FAIL(player);
7563 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7565 /* clean found audio decoders */
7566 if (player->audio_decoders) {
7567 GList *a_dec = player->audio_decoders;
7568 for (; a_dec; a_dec = g_list_next(a_dec)) {
7569 gchar *name = a_dec->data;
7570 MMPLAYER_FREEIF(name);
7572 g_list_free(player->audio_decoders);
7573 player->audio_decoders = NULL;
7576 /* clean the uri list except original uri */
7577 if (player->uri_info.uri_list) {
7578 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7580 if (player->attrs) {
7581 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7582 LOGD("restore original uri = %s", original_uri);
7584 if (mm_attrs_commit_all(player->attrs))
7585 LOGE("failed to commit the original uri.");
7588 GList *uri_list = player->uri_info.uri_list;
7589 for (; uri_list; uri_list = g_list_next(uri_list)) {
7590 gchar *uri = uri_list->data;
7591 MMPLAYER_FREEIF(uri);
7593 g_list_free(player->uri_info.uri_list);
7594 player->uri_info.uri_list = NULL;
7597 /* clear the audio stream buffer list */
7598 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7600 /* clear the video stream bo list */
7601 __mmplayer_video_stream_destroy_bo_list(player);
7602 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7604 if (player->profile.input_mem.buf) {
7605 free(player->profile.input_mem.buf);
7606 player->profile.input_mem.buf = NULL;
7608 player->profile.input_mem.len = 0;
7609 player->profile.input_mem.offset = 0;
7611 player->uri_info.uri_idx = 0;
7616 __mmplayer_check_subtitle(mmplayer_t *player)
7618 MMHandleType attrs = 0;
7619 char *subtitle_uri = NULL;
7623 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7625 /* get subtitle attribute */
7626 attrs = MMPLAYER_GET_ATTRS(player);
7630 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7631 if (!subtitle_uri || !strlen(subtitle_uri))
7634 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7635 player->is_external_subtitle_present = TRUE;
7643 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7645 MMPLAYER_RETURN_IF_FAIL(player);
7647 if (player->eos_timer) {
7648 LOGD("cancel eos timer");
7649 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7650 player->eos_timer = 0;
7657 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7661 MMPLAYER_RETURN_IF_FAIL(player);
7662 MMPLAYER_RETURN_IF_FAIL(sink);
7664 player->sink_elements = g_list_append(player->sink_elements, sink);
7670 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7674 MMPLAYER_RETURN_IF_FAIL(player);
7675 MMPLAYER_RETURN_IF_FAIL(sink);
7677 player->sink_elements = g_list_remove(player->sink_elements, sink);
7683 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7684 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7686 mmplayer_signal_item_t *item = NULL;
7689 MMPLAYER_RETURN_IF_FAIL(player);
7691 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7692 LOGE("invalid signal type [%d]", type);
7696 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7698 LOGE("cannot connect signal [%s]", signal);
7703 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7704 player->signals[type] = g_list_append(player->signals[type], item);
7710 /* NOTE : be careful with calling this api. please refer to below glib comment
7711 * glib comment : Note that there is a bug in GObject that makes this function much
7712 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7713 * will no longer be called, but, the signal handler is not currently disconnected.
7714 * If the instance is itself being freed at the same time than this doesn't matter,
7715 * since the signal will automatically be removed, but if instance persists,
7716 * then the signal handler will leak. You should not remove the signal yourself
7717 * because in a future versions of GObject, the handler will automatically be
7720 * It's possible to work around this problem in a way that will continue to work
7721 * with future versions of GObject by checking that the signal handler is still
7722 * connected before disconnected it:
7724 * if (g_signal_handler_is_connected(instance, id))
7725 * g_signal_handler_disconnect(instance, id);
7728 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7730 GList *sig_list = NULL;
7731 mmplayer_signal_item_t *item = NULL;
7735 MMPLAYER_RETURN_IF_FAIL(player);
7737 LOGD("release signals type : %d", type);
7739 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7740 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7741 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7743 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7744 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7748 sig_list = player->signals[type];
7750 for (; sig_list; sig_list = sig_list->next) {
7751 item = sig_list->data;
7753 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7754 if (g_signal_handler_is_connected(item->obj, item->sig))
7755 g_signal_handler_disconnect(item->obj, item->sig);
7758 MMPLAYER_FREEIF(item);
7761 g_list_free(player->signals[type]);
7762 player->signals[type] = NULL;
7770 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7772 mmplayer_t *player = 0;
7773 int prev_display_surface_type = 0;
7774 void *prev_display_overlay = NULL;
7778 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7779 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7781 player = MM_PLAYER_CAST(handle);
7783 /* check video sinkbin is created */
7784 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7785 LOGE("Videosink is already created");
7786 return MM_ERROR_NONE;
7789 LOGD("videosink element is not yet ready");
7791 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7792 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7794 return MM_ERROR_INVALID_ARGUMENT;
7797 /* load previous attributes */
7798 if (player->attrs) {
7799 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7800 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7801 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7802 if (prev_display_surface_type == surface_type) {
7803 LOGD("incoming display surface type is same as previous one, do nothing..");
7805 return MM_ERROR_NONE;
7808 LOGE("failed to load attributes");
7810 return MM_ERROR_PLAYER_INTERNAL;
7813 /* videobin is not created yet, so we just set attributes related to display surface */
7814 LOGD("store display attribute for given surface type(%d)", surface_type);
7815 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7816 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7817 if (mm_attrs_commit_all(player->attrs)) {
7818 LOGE("failed to commit attribute");
7820 return MM_ERROR_PLAYER_INTERNAL;
7824 return MM_ERROR_NONE;
7827 /* Note : if silent is true, then subtitle would not be displayed. :*/
7829 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7831 mmplayer_t *player = (mmplayer_t *)hplayer;
7835 /* check player handle */
7836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7838 player->set_mode.subtitle_off = silent;
7840 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7844 return MM_ERROR_NONE;
7848 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7850 mmplayer_gst_element_t *mainbin = NULL;
7851 mmplayer_gst_element_t *textbin = NULL;
7852 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7853 GstState current_state = GST_STATE_VOID_PENDING;
7854 GstState element_state = GST_STATE_VOID_PENDING;
7855 GstState element_pending_state = GST_STATE_VOID_PENDING;
7857 GstEvent *event = NULL;
7858 int result = MM_ERROR_NONE;
7860 GstClock *curr_clock = NULL;
7861 GstClockTime base_time, start_time, curr_time;
7866 /* check player handle */
7867 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7869 player->pipeline->mainbin &&
7870 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7872 mainbin = player->pipeline->mainbin;
7873 textbin = player->pipeline->textbin;
7875 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7877 // sync clock with current pipeline
7878 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7879 curr_time = gst_clock_get_time(curr_clock);
7881 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7882 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7884 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7885 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7887 if (current_state > GST_STATE_READY) {
7888 // sync state with current pipeline
7889 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7890 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7891 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7893 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7894 if (GST_STATE_CHANGE_FAILURE == ret) {
7895 LOGE("fail to state change.");
7896 result = MM_ERROR_PLAYER_INTERNAL;
7900 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7901 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7904 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7905 gst_object_unref(curr_clock);
7908 // seek to current position
7909 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7910 result = MM_ERROR_PLAYER_INVALID_STATE;
7911 LOGE("gst_element_query_position failed, invalid state");
7915 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7916 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);
7918 _mmplayer_gst_send_event_to_sink(player, event);
7920 result = MM_ERROR_PLAYER_INTERNAL;
7921 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7925 /* sync state with current pipeline */
7926 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7927 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7928 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7930 return MM_ERROR_NONE;
7933 /* release text pipeline resource */
7934 player->textsink_linked = 0;
7936 /* release signal */
7937 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7939 /* release textbin with it's childs */
7940 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7941 MMPLAYER_FREEIF(player->pipeline->textbin);
7942 player->pipeline->textbin = NULL;
7944 /* release subtitle elem */
7945 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7946 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7952 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7954 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7955 GstState current_state = GST_STATE_VOID_PENDING;
7957 MMHandleType attrs = 0;
7958 mmplayer_gst_element_t *mainbin = NULL;
7959 mmplayer_gst_element_t *textbin = NULL;
7961 gchar *subtitle_uri = NULL;
7962 int result = MM_ERROR_NONE;
7963 const gchar *charset = NULL;
7967 /* check player handle */
7968 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7970 player->pipeline->mainbin &&
7971 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7972 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7974 mainbin = player->pipeline->mainbin;
7975 textbin = player->pipeline->textbin;
7977 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7978 if (current_state < GST_STATE_READY) {
7979 result = MM_ERROR_PLAYER_INVALID_STATE;
7980 LOGE("Pipeline is not in proper state");
7984 attrs = MMPLAYER_GET_ATTRS(player);
7986 LOGE("cannot get content attribute");
7987 result = MM_ERROR_PLAYER_INTERNAL;
7991 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7992 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7993 LOGE("subtitle uri is not proper filepath");
7994 result = MM_ERROR_PLAYER_INVALID_URI;
7998 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7999 LOGE("failed to get storage info of subtitle path");
8000 result = MM_ERROR_PLAYER_INVALID_URI;
8004 LOGD("old subtitle file path is [%s]", subtitle_uri);
8005 LOGD("new subtitle file path is [%s]", filepath);
8007 if (!strcmp(filepath, subtitle_uri)) {
8008 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8011 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8012 if (mm_attrs_commit_all(player->attrs)) {
8013 LOGE("failed to commit.");
8018 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8019 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8020 player->subtitle_language_list = NULL;
8021 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8023 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8024 if (ret != GST_STATE_CHANGE_SUCCESS) {
8025 LOGE("failed to change state of textbin to READY");
8026 result = MM_ERROR_PLAYER_INTERNAL;
8030 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8031 if (ret != GST_STATE_CHANGE_SUCCESS) {
8032 LOGE("failed to change state of subparse to READY");
8033 result = MM_ERROR_PLAYER_INTERNAL;
8037 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8038 if (ret != GST_STATE_CHANGE_SUCCESS) {
8039 LOGE("failed to change state of filesrc to READY");
8040 result = MM_ERROR_PLAYER_INTERNAL;
8044 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8046 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8048 charset = _mmplayer_get_charset(filepath);
8050 LOGD("detected charset is %s", charset);
8051 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8054 result = _mmplayer_sync_subtitle_pipeline(player);
8061 /* API to switch between external subtitles */
8063 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8065 int result = MM_ERROR_NONE;
8066 mmplayer_t *player = (mmplayer_t *)hplayer;
8071 /* check player handle */
8072 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8074 /* filepath can be null in idle state */
8076 /* check file path */
8077 if ((path = strstr(filepath, "file://")))
8078 result = _mmplayer_exist_file_path(path + 7);
8080 result = _mmplayer_exist_file_path(filepath);
8082 if (result != MM_ERROR_NONE) {
8083 LOGE("invalid subtitle path 0x%X", result);
8084 return result; /* file not found or permission denied */
8088 if (!player->pipeline) {
8090 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8091 if (mm_attrs_commit_all(player->attrs)) {
8092 LOGE("failed to commit"); /* subtitle path will not be created */
8093 return MM_ERROR_PLAYER_INTERNAL;
8096 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8097 /* check filepath */
8098 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8100 if (!__mmplayer_check_subtitle(player)) {
8101 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8102 if (mm_attrs_commit_all(player->attrs)) {
8103 LOGE("failed to commit");
8104 return MM_ERROR_PLAYER_INTERNAL;
8107 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8108 LOGE("fail to create text pipeline");
8109 return MM_ERROR_PLAYER_INTERNAL;
8112 result = _mmplayer_sync_subtitle_pipeline(player);
8114 result = __mmplayer_change_external_subtitle_language(player, filepath);
8117 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8118 player->is_external_subtitle_added_now = TRUE;
8120 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8121 if (!player->subtitle_language_list) {
8122 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8123 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8124 LOGW("subtitle language list is not updated yet");
8126 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8134 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8136 int result = MM_ERROR_NONE;
8137 gchar *change_pad_name = NULL;
8138 GstPad *sinkpad = NULL;
8139 mmplayer_gst_element_t *mainbin = NULL;
8140 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8141 GstCaps *caps = NULL;
8142 gint total_track_num = 0;
8146 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8147 MM_ERROR_PLAYER_NOT_INITIALIZED);
8149 LOGD("Change Track(%d) to %d", type, index);
8151 mainbin = player->pipeline->mainbin;
8153 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8154 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8155 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8156 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8158 /* Changing Video Track is not supported. */
8159 LOGE("Track Type Error");
8163 if (mainbin[elem_idx].gst == NULL) {
8164 result = MM_ERROR_PLAYER_NO_OP;
8165 LOGD("Req track doesn't exist");
8169 total_track_num = player->selector[type].total_track_num;
8170 if (total_track_num <= 0) {
8171 result = MM_ERROR_PLAYER_NO_OP;
8172 LOGD("Language list is not available");
8176 if ((index < 0) || (index >= total_track_num)) {
8177 result = MM_ERROR_INVALID_ARGUMENT;
8178 LOGD("Not a proper index : %d", index);
8182 /*To get the new pad from the selector*/
8183 change_pad_name = g_strdup_printf("sink_%u", index);
8184 if (change_pad_name == NULL) {
8185 result = MM_ERROR_PLAYER_INTERNAL;
8186 LOGD("Pad does not exists");
8190 LOGD("new active pad name: %s", change_pad_name);
8192 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8193 if (sinkpad == NULL) {
8194 LOGD("sinkpad is NULL");
8195 result = MM_ERROR_PLAYER_INTERNAL;
8199 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8200 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8202 caps = gst_pad_get_current_caps(sinkpad);
8203 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8206 gst_object_unref(sinkpad);
8208 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8209 __mmplayer_set_audio_attrs(player, caps);
8212 MMPLAYER_FREEIF(change_pad_name);
8217 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8219 int result = MM_ERROR_NONE;
8220 mmplayer_t *player = NULL;
8221 mmplayer_gst_element_t *mainbin = NULL;
8223 gint current_active_index = 0;
8225 GstState current_state = GST_STATE_VOID_PENDING;
8226 GstEvent *event = NULL;
8231 player = (mmplayer_t *)hplayer;
8232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8234 if (!player->pipeline) {
8235 LOGE("Track %d pre setting -> %d", type, index);
8237 player->selector[type].active_pad_index = index;
8241 mainbin = player->pipeline->mainbin;
8243 current_active_index = player->selector[type].active_pad_index;
8245 /*If index is same as running index no need to change the pad*/
8246 if (current_active_index == index)
8249 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8250 result = MM_ERROR_PLAYER_INVALID_STATE;
8254 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8255 if (current_state < GST_STATE_PAUSED) {
8256 result = MM_ERROR_PLAYER_INVALID_STATE;
8257 LOGW("Pipeline not in porper state");
8261 result = __mmplayer_change_selector_pad(player, type, index);
8262 if (result != MM_ERROR_NONE) {
8263 LOGE("change selector pad error");
8267 player->selector[type].active_pad_index = index;
8269 if (current_state == GST_STATE_PLAYING) {
8270 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8271 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8272 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8274 _mmplayer_gst_send_event_to_sink(player, event);
8276 result = MM_ERROR_PLAYER_INTERNAL;
8286 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8288 mmplayer_t *player = (mmplayer_t *)hplayer;
8292 /* check player handle */
8293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8295 *silent = player->set_mode.subtitle_off;
8297 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8301 return MM_ERROR_NONE;
8305 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8307 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8308 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8310 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8311 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8315 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8316 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8317 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8318 mmplayer_dump_t *dump_s;
8319 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8320 if (dump_s == NULL) {
8321 LOGE("malloc fail");
8325 dump_s->dump_element_file = NULL;
8326 dump_s->dump_pad = NULL;
8327 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8329 if (dump_s->dump_pad) {
8330 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8331 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]);
8332 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8333 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);
8334 /* add list for removed buffer probe and close FILE */
8335 player->dump_list = g_list_append(player->dump_list, dump_s);
8336 LOGD("%s sink pad added buffer probe for dump", factory_name);
8339 MMPLAYER_FREEIF(dump_s);
8340 LOGE("failed to get %s sink pad added", factory_name);
8347 static GstPadProbeReturn
8348 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8350 FILE *dump_data = (FILE *)u_data;
8352 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8353 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8355 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8357 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8359 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8361 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8363 gst_buffer_unmap(buffer, &probe_info);
8365 return GST_PAD_PROBE_OK;
8369 __mmplayer_release_dump_list(GList *dump_list)
8371 GList *d_list = dump_list;
8376 for (; d_list; d_list = g_list_next(d_list)) {
8377 mmplayer_dump_t *dump_s = d_list->data;
8378 if (dump_s->dump_pad) {
8379 if (dump_s->probe_handle_id)
8380 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8381 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8383 if (dump_s->dump_element_file) {
8384 fclose(dump_s->dump_element_file);
8385 dump_s->dump_element_file = NULL;
8387 MMPLAYER_FREEIF(dump_s);
8389 g_list_free(dump_list);
8394 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8396 mmplayer_t *player = (mmplayer_t *)hplayer;
8400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8401 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8403 *exist = (bool)player->has_closed_caption;
8407 return MM_ERROR_NONE;
8411 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8415 // LOGD("unref internal gst buffer %p", buffer);
8416 gst_buffer_unref((GstBuffer *)buffer);
8423 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8425 mmplayer_t *player = (mmplayer_t *)hplayer;
8429 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8430 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8432 if (MMPLAYER_IS_STREAMING(player))
8433 *timeout = (int)player->ini.live_state_change_timeout;
8435 *timeout = (int)player->ini.localplayback_state_change_timeout;
8437 LOGD("timeout = %d", *timeout);
8440 return MM_ERROR_NONE;
8444 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8446 mmplayer_t *player = (mmplayer_t *)hplayer;
8450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8451 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8453 *num = player->video_num_buffers;
8454 *extra_num = player->video_extra_num_buffers;
8456 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8459 return MM_ERROR_NONE;
8463 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8467 MMPLAYER_RETURN_IF_FAIL(player);
8469 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8471 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8472 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8473 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8474 player->storage_info[i].id = -1;
8475 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8477 if (path_type != MMPLAYER_PATH_MAX)
8486 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8488 int ret = MM_ERROR_NONE;
8489 mmplayer_t *player = (mmplayer_t *)hplayer;
8490 MMMessageParamType msg_param = {0, };
8493 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8495 LOGW("state changed storage %d:%d", id, state);
8497 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8498 return MM_ERROR_NONE;
8500 /* FIXME: text path should be handled seperately. */
8501 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8502 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8503 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8504 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8505 LOGW("external storage is removed");
8507 if (player->msg_posted == FALSE) {
8508 memset(&msg_param, 0, sizeof(MMMessageParamType));
8509 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8510 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8511 player->msg_posted = TRUE;
8514 /* unrealize the player */
8515 ret = _mmplayer_unrealize(hplayer);
8516 if (ret != MM_ERROR_NONE)
8517 LOGE("failed to unrealize");
8525 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8527 int ret = MM_ERROR_NONE;
8528 mmplayer_t *player = (mmplayer_t *)hplayer;
8529 int idx = 0, total = 0;
8530 gchar *result = NULL, *tmp = NULL;
8533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8534 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8536 total = *num = g_list_length(player->adaptive_info.var_list);
8538 LOGW("There is no stream variant info.");
8542 result = g_strdup("");
8543 for (idx = 0 ; idx < total ; idx++) {
8544 stream_variant_t *v_data = NULL;
8545 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8548 gchar data[64] = {0};
8549 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8551 tmp = g_strconcat(result, data, NULL);
8555 LOGW("There is no variant data in %d", idx);
8560 *var_info = (char *)result;
8562 LOGD("variant info %d:%s", *num, *var_info);
8568 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8570 int ret = MM_ERROR_NONE;
8571 mmplayer_t *player = (mmplayer_t *)hplayer;
8574 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8576 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8578 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8579 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8580 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8582 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8583 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8584 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8585 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8587 /* FIXME: seek to current position for applying new variant limitation */
8596 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8598 int ret = MM_ERROR_NONE;
8599 mmplayer_t *player = (mmplayer_t *)hplayer;
8602 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8603 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8605 *bandwidth = player->adaptive_info.limit.bandwidth;
8606 *width = player->adaptive_info.limit.width;
8607 *height = player->adaptive_info.limit.height;
8609 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8616 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8618 int ret = MM_ERROR_NONE;
8619 mmplayer_t *player = (mmplayer_t *)hplayer;
8622 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8623 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8624 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8626 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8628 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8629 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8630 else /* live case */
8631 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8633 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8640 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8642 #define IDX_FIRST_SW_CODEC 0
8643 mmplayer_t *player = (mmplayer_t *)hplayer;
8644 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8645 MMHandleType attrs = 0;
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8650 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8651 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8652 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8654 switch (stream_type) {
8655 case MM_PLAYER_STREAM_TYPE_AUDIO:
8656 /* to support audio codec selection, codec info have to be added in ini file as below.
8657 audio codec element hw = xxxx
8658 audio codec element sw = avdec */
8659 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8660 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8661 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8662 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8663 LOGE("There is no audio codec info for codec_type %d", codec_type);
8664 return MM_ERROR_PLAYER_NO_OP;
8667 case MM_PLAYER_STREAM_TYPE_VIDEO:
8668 /* to support video codec selection, codec info have to be added in ini file as below.
8669 video codec element hw = omx
8670 video codec element sw = avdec */
8671 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8672 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8673 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8674 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8675 LOGE("There is no video codec info for codec_type %d", codec_type);
8676 return MM_ERROR_PLAYER_NO_OP;
8680 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8681 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8685 LOGD("update %s codec_type to %d", attr_name, codec_type);
8687 attrs = MMPLAYER_GET_ATTRS(player);
8688 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8690 if (mm_attrs_commit_all(player->attrs)) {
8691 LOGE("failed to commit codec_type attributes");
8692 return MM_ERROR_PLAYER_INTERNAL;
8696 return MM_ERROR_NONE;
8700 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8702 mmplayer_t *player = (mmplayer_t *)hplayer;
8703 GstElement *rg_vol_element = NULL;
8707 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8709 player->sound.rg_enable = enabled;
8711 /* just hold rgvolume enable value if pipeline is not ready */
8712 if (!player->pipeline || !player->pipeline->audiobin) {
8713 LOGD("pipeline is not ready. holding rgvolume enable value");
8714 return MM_ERROR_NONE;
8717 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8719 if (!rg_vol_element) {
8720 LOGD("rgvolume element is not created");
8721 return MM_ERROR_PLAYER_INTERNAL;
8725 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8727 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8731 return MM_ERROR_NONE;
8735 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8737 mmplayer_t *player = (mmplayer_t *)hplayer;
8738 GstElement *rg_vol_element = NULL;
8739 gboolean enable = FALSE;
8743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8744 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8746 /* just hold enable_rg value if pipeline is not ready */
8747 if (!player->pipeline || !player->pipeline->audiobin) {
8748 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8749 *enabled = player->sound.rg_enable;
8750 return MM_ERROR_NONE;
8753 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8755 if (!rg_vol_element) {
8756 LOGD("rgvolume element is not created");
8757 return MM_ERROR_PLAYER_INTERNAL;
8760 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8761 *enabled = (bool)enable;
8765 return MM_ERROR_NONE;
8769 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8771 mmplayer_t *player = (mmplayer_t *)hplayer;
8772 MMHandleType attrs = 0;
8773 void *handle = NULL;
8774 int ret = MM_ERROR_NONE;
8778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8780 attrs = MMPLAYER_GET_ATTRS(player);
8781 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8783 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8785 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8786 return MM_ERROR_PLAYER_INTERNAL;
8789 player->video_roi.scale_x = scale_x;
8790 player->video_roi.scale_y = scale_y;
8791 player->video_roi.scale_width = scale_width;
8792 player->video_roi.scale_height = scale_height;
8794 /* check video sinkbin is created */
8795 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8796 return MM_ERROR_NONE;
8798 if (!gst_video_overlay_set_video_roi_area(
8799 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8800 scale_x, scale_y, scale_width, scale_height))
8801 ret = MM_ERROR_PLAYER_INTERNAL;
8803 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8804 scale_x, scale_y, scale_width, scale_height);
8812 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8814 mmplayer_t *player = (mmplayer_t *)hplayer;
8815 int ret = MM_ERROR_NONE;
8819 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8820 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8822 *scale_x = player->video_roi.scale_x;
8823 *scale_y = player->video_roi.scale_y;
8824 *scale_width = player->video_roi.scale_width;
8825 *scale_height = player->video_roi.scale_height;
8827 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8828 *scale_x, *scale_y, *scale_width, *scale_height);
8834 __mmplayer_update_duration_value(mmplayer_t *player)
8836 gboolean ret = FALSE;
8837 gint64 dur_nsec = 0;
8838 LOGD("try to update duration");
8840 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8841 player->duration = dur_nsec;
8842 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8846 if (player->duration < 0) {
8847 LOGW("duration is Non-Initialized !!!");
8848 player->duration = 0;
8851 /* update streaming service type */
8852 player->streaming_type = _mmplayer_get_stream_service_type(player);
8854 /* check duration is OK */
8855 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8856 /* FIXIT : find another way to get duration here. */
8857 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8863 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8865 /* update audio params
8866 NOTE : We need original audio params and it can be only obtained from src pad of audio
8867 decoder. Below code only valid when we are not using 'resampler' just before
8868 'audioconverter'. */
8869 GstCaps *caps_a = NULL;
8871 gint samplerate = 0, channels = 0;
8872 GstStructure *p = NULL;
8873 GstElement *aconv = NULL;
8875 LOGD("try to update audio attrs");
8877 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8879 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8880 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8881 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8882 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8884 LOGE("there is no audio converter");
8888 pad = gst_element_get_static_pad(aconv, "sink");
8891 LOGW("failed to get pad from audio converter");
8895 caps_a = gst_pad_get_current_caps(pad);
8897 LOGW("not ready to get audio caps");
8898 gst_object_unref(pad);
8902 p = gst_caps_get_structure(caps_a, 0);
8904 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8906 gst_structure_get_int(p, "rate", &samplerate);
8907 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8909 gst_structure_get_int(p, "channels", &channels);
8910 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8912 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8914 gst_caps_unref(caps_a);
8915 gst_object_unref(pad);
8921 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8923 LOGD("try to update video attrs");
8925 GstCaps *caps_v = NULL;
8929 GstStructure *p = NULL;
8931 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8932 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8934 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8936 LOGD("no videosink sink pad");
8940 caps_v = gst_pad_get_current_caps(pad);
8941 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8942 if (!caps_v && player->v_stream_caps) {
8943 caps_v = player->v_stream_caps;
8944 gst_caps_ref(caps_v);
8948 LOGD("no negitiated caps from videosink");
8949 gst_object_unref(pad);
8953 p = gst_caps_get_structure(caps_v, 0);
8954 gst_structure_get_int(p, "width", &width);
8955 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8957 gst_structure_get_int(p, "height", &height);
8958 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8960 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8962 SECURE_LOGD("width : %d height : %d", width, height);
8964 gst_caps_unref(caps_v);
8965 gst_object_unref(pad);
8968 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8969 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8976 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8978 gboolean ret = FALSE;
8979 guint64 data_size = 0;
8983 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8984 if (!player->duration)
8987 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8988 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8989 if (stat(path, &sb) == 0)
8990 data_size = (guint64)sb.st_size;
8992 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8993 data_size = player->http_content_size;
8996 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8999 guint64 bitrate = 0;
9000 guint64 msec_dur = 0;
9002 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9004 bitrate = data_size * 8 * 1000 / msec_dur;
9005 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9006 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9010 LOGD("player duration is less than 0");
9014 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9015 if (player->total_bitrate) {
9016 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9025 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9027 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9028 data->uri_type = uri_type;
9032 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9034 int ret = MM_ERROR_PLAYER_INVALID_URI;
9036 char *buffer = NULL;
9037 char *seperator = strchr(path, ',');
9038 char ext[100] = {0,}, size[100] = {0,};
9041 if ((buffer = strstr(path, "ext="))) {
9042 buffer += strlen("ext=");
9044 if (strlen(buffer)) {
9045 strncpy(ext, buffer, 99);
9047 if ((seperator = strchr(ext, ','))
9048 || (seperator = strchr(ext, ' '))
9049 || (seperator = strchr(ext, '\0'))) {
9050 seperator[0] = '\0';
9055 if ((buffer = strstr(path, "size="))) {
9056 buffer += strlen("size=");
9058 if (strlen(buffer) > 0) {
9059 strncpy(size, buffer, 99);
9061 if ((seperator = strchr(size, ','))
9062 || (seperator = strchr(size, ' '))
9063 || (seperator = strchr(size, '\0'))) {
9064 seperator[0] = '\0';
9067 mem_size = atoi(size);
9072 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9074 if (mem_size && param) {
9075 if (data->input_mem.buf)
9076 free(data->input_mem.buf);
9077 data->input_mem.buf = malloc(mem_size);
9079 if (data->input_mem.buf) {
9080 memcpy(data->input_mem.buf, param, mem_size);
9081 data->input_mem.len = mem_size;
9082 ret = MM_ERROR_NONE;
9084 LOGE("failed to alloc mem %d", mem_size);
9085 ret = MM_ERROR_PLAYER_INTERNAL;
9088 data->input_mem.offset = 0;
9089 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9096 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9098 gchar *location = NULL;
9101 int ret = MM_ERROR_NONE;
9103 if ((path = strstr(uri, "file://"))) {
9104 location = g_filename_from_uri(uri, NULL, &err);
9105 if (!location || (err != NULL)) {
9106 LOGE("Invalid URI '%s' for filesrc: %s", path,
9107 (err != NULL) ? err->message : "unknown error");
9111 MMPLAYER_FREEIF(location);
9113 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9114 return MM_ERROR_PLAYER_INVALID_URI;
9116 LOGD("path from uri: %s", location);
9119 path = (location != NULL) ? (location) : ((char *)uri);
9122 ret = _mmplayer_exist_file_path(path);
9124 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9125 if (ret == MM_ERROR_NONE) {
9126 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9127 if (_mmplayer_is_sdp_file(path)) {
9128 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9129 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9131 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9133 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9134 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9136 LOGE("invalid uri, could not play..");
9137 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9140 MMPLAYER_FREEIF(location);
9145 static mmplayer_video_decoded_data_info_t *
9146 __mmplayer_create_stream_from_pad(GstPad *pad)
9148 GstCaps *caps = NULL;
9149 GstStructure *structure = NULL;
9150 unsigned int fourcc = 0;
9151 const gchar *string_format = NULL;
9152 mmplayer_video_decoded_data_info_t *stream = NULL;
9154 MMPixelFormatType format;
9157 caps = gst_pad_get_current_caps(pad);
9159 LOGE("Caps is NULL.");
9163 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9164 structure = gst_caps_get_structure(caps, 0);
9165 gst_structure_get_int(structure, "width", &width);
9166 gst_structure_get_int(structure, "height", &height);
9167 string_format = gst_structure_get_string(structure, "format");
9170 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9171 format = _mmplayer_get_pixtype(fourcc);
9172 gst_video_info_from_caps(&info, caps);
9173 gst_caps_unref(caps);
9176 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9177 LOGE("Wrong condition!!");
9181 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9183 LOGE("failed to alloc mem for video data");
9187 stream->width = width;
9188 stream->height = height;
9189 stream->format = format;
9190 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9196 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9198 unsigned int pitch = 0;
9199 unsigned int size = 0;
9201 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9204 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9205 bo = gst_tizen_memory_get_bos(mem, index);
9207 stream->bo[index] = tbm_bo_ref(bo);
9209 LOGE("failed to get bo for index %d", index);
9212 for (index = 0; index < stream->plane_num; index++) {
9213 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9214 stream->stride[index] = pitch;
9216 stream->elevation[index] = size / pitch;
9218 stream->elevation[index] = stream->height;
9223 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9225 if (stream->format == MM_PIXEL_FORMAT_I420) {
9226 int ret = TBM_SURFACE_ERROR_NONE;
9227 tbm_surface_h surface;
9228 tbm_surface_info_s info;
9230 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9232 ret = tbm_surface_get_info(surface, &info);
9233 if (ret != TBM_SURFACE_ERROR_NONE) {
9234 tbm_surface_destroy(surface);
9238 tbm_surface_destroy(surface);
9239 stream->stride[0] = info.planes[0].stride;
9240 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9241 stream->stride[1] = info.planes[1].stride;
9242 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9243 stream->stride[2] = info.planes[2].stride;
9244 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9245 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9246 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9247 stream->stride[0] = stream->width * 4;
9248 stream->elevation[0] = stream->height;
9249 stream->bo_size = stream->stride[0] * stream->height;
9251 LOGE("Not support format %d", stream->format);
9259 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9261 tbm_bo_handle thandle;
9263 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9264 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9265 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9269 unsigned char *src = NULL;
9270 unsigned char *dest = NULL;
9271 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9273 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9275 LOGE("fail to gst_memory_map");
9279 if (!mapinfo.data) {
9280 LOGE("data pointer is wrong");
9284 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9285 if (!stream->bo[0]) {
9286 LOGE("Fail to tbm_bo_alloc!!");
9290 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9292 LOGE("thandle pointer is wrong");
9296 if (stream->format == MM_PIXEL_FORMAT_I420) {
9297 src_stride[0] = GST_ROUND_UP_4(stream->width);
9298 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9299 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9300 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9303 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9304 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9306 for (i = 0; i < 3; i++) {
9307 src = mapinfo.data + src_offset[i];
9308 dest = thandle.ptr + dest_offset[i];
9313 for (j = 0; j < stream->height >> k; j++) {
9314 memcpy(dest, src, stream->width>>k);
9315 src += src_stride[i];
9316 dest += stream->stride[i];
9319 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9320 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9322 LOGE("Not support format %d", stream->format);
9326 tbm_bo_unmap(stream->bo[0]);
9327 gst_memory_unmap(mem, &mapinfo);
9333 tbm_bo_unmap(stream->bo[0]);
9336 gst_memory_unmap(mem, &mapinfo);
9342 __mmplayer_set_pause_state(mmplayer_t *player)
9344 if (player->sent_bos)
9347 /* rtsp case, get content attrs by GstMessage */
9348 if (MMPLAYER_IS_RTSP_STREAMING(player))
9351 /* it's first time to update all content attrs. */
9352 _mmplayer_update_content_attrs(player, ATTR_ALL);
9356 __mmplayer_set_playing_state(mmplayer_t *player)
9358 gchar *audio_codec = NULL;
9360 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9361 /* initialize because auto resume is done well. */
9362 player->resumed_by_rewind = FALSE;
9363 player->playback_rate = 1.0;
9366 if (player->sent_bos)
9369 /* try to get content metadata */
9371 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9372 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9373 * legacy mmfw-player api
9375 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9377 if ((player->cmd == MMPLAYER_COMMAND_START)
9378 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9379 __mmplayer_handle_missed_plugin(player);
9382 /* check audio codec field is set or not
9383 * we can get it from typefinder or codec's caps.
9385 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9387 /* The codec format can't be sent for audio only case like amr, mid etc.
9388 * Because, parser don't make related TAG.
9389 * So, if it's not set yet, fill it with found data.
9392 if (g_strrstr(player->type, "audio/midi"))
9393 audio_codec = "MIDI";
9394 else if (g_strrstr(player->type, "audio/x-amr"))
9395 audio_codec = "AMR";
9396 else if (g_strrstr(player->type, "audio/mpeg")
9397 && !g_strrstr(player->type, "mpegversion=(int)1"))
9398 audio_codec = "AAC";
9400 audio_codec = "unknown";
9402 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9404 if (mm_attrs_commit_all(player->attrs))
9405 LOGE("failed to update attributes");
9407 LOGD("set audio codec type with caps");