4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
278 if (mm_attrs_commit_all(attrs)) {
279 LOGE("failed to update attributes");
289 _mmplayer_get_stream_service_type(mmplayer_t *player)
291 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
297 player->pipeline->mainbin &&
298 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
299 STREAMING_SERVICE_NONE);
301 /* streaming service type if streaming */
302 if (!MMPLAYER_IS_STREAMING(player))
303 return STREAMING_SERVICE_NONE;
305 streaming_type = (player->duration == 0) ?
306 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
308 switch (streaming_type) {
309 case STREAMING_SERVICE_LIVE:
310 LOGD("it's live streaming");
312 case STREAMING_SERVICE_VOD:
313 LOGD("it's vod streaming");
316 LOGE("should not get here");
322 return streaming_type;
325 /* this function sets the player state and also report
326 * it to applicaton by calling callback function
329 _mmplayer_set_state(mmplayer_t *player, int state)
331 MMMessageParamType msg = {0, };
333 MMPLAYER_RETURN_IF_FAIL(player);
335 if (MMPLAYER_CURRENT_STATE(player) == state) {
336 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
337 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
341 /* update player states */
342 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
343 MMPLAYER_CURRENT_STATE(player) = state;
345 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
346 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
349 MMPLAYER_PRINT_STATE(player);
351 switch (MMPLAYER_CURRENT_STATE(player)) {
352 case MM_PLAYER_STATE_NULL:
353 case MM_PLAYER_STATE_READY:
355 case MM_PLAYER_STATE_PAUSED:
356 __mmplayer_set_pause_state(player);
358 case MM_PLAYER_STATE_PLAYING:
359 __mmplayer_set_playing_state(player);
361 case MM_PLAYER_STATE_NONE:
363 LOGW("invalid target state, there is nothing to do.");
368 /* post message to application */
369 if (MMPLAYER_TARGET_STATE(player) == state) {
370 /* fill the message with state of player */
371 msg.union_type = MM_MSG_UNION_STATE;
372 msg.state.previous = MMPLAYER_PREV_STATE(player);
373 msg.state.current = MMPLAYER_CURRENT_STATE(player);
375 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
377 /* state changed by resource callback */
378 if (player->interrupted_by_resource)
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
380 else /* state changed by usecase */
381 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
384 LOGD("intermediate state, do nothing.");
385 MMPLAYER_PRINT_STATE(player);
389 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
390 && !player->sent_bos) {
391 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
392 player->sent_bos = TRUE;
399 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
401 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
402 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
404 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
406 LOGD("incomming command : %d ", command);
408 current_state = MMPLAYER_CURRENT_STATE(player);
409 pending_state = MMPLAYER_PENDING_STATE(player);
411 MMPLAYER_PRINT_STATE(player);
414 case MMPLAYER_COMMAND_CREATE:
416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
418 if (current_state == MM_PLAYER_STATE_NULL ||
419 current_state == MM_PLAYER_STATE_READY ||
420 current_state == MM_PLAYER_STATE_PAUSED ||
421 current_state == MM_PLAYER_STATE_PLAYING)
426 case MMPLAYER_COMMAND_DESTROY:
428 /* destroy can called anytime */
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
434 case MMPLAYER_COMMAND_REALIZE:
436 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
438 if (pending_state != MM_PLAYER_STATE_NONE) {
441 /* need ready state to realize */
442 if (current_state == MM_PLAYER_STATE_READY)
445 if (current_state != MM_PLAYER_STATE_NULL)
451 case MMPLAYER_COMMAND_UNREALIZE:
453 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
455 if (current_state == MM_PLAYER_STATE_NULL)
460 case MMPLAYER_COMMAND_START:
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
464 if (pending_state == MM_PLAYER_STATE_NONE) {
465 if (current_state == MM_PLAYER_STATE_PLAYING)
467 else if (current_state != MM_PLAYER_STATE_READY &&
468 current_state != MM_PLAYER_STATE_PAUSED)
470 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
472 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
473 LOGD("player is going to paused state, just change the pending state as playing");
480 case MMPLAYER_COMMAND_STOP:
482 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
484 if (current_state == MM_PLAYER_STATE_READY)
487 /* need playing/paused state to stop */
488 if (current_state != MM_PLAYER_STATE_PLAYING &&
489 current_state != MM_PLAYER_STATE_PAUSED)
494 case MMPLAYER_COMMAND_PAUSE:
496 if (MMPLAYER_IS_LIVE_STREAMING(player))
499 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
500 goto NOT_COMPLETED_SEEK;
502 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
504 if (pending_state == MM_PLAYER_STATE_NONE) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
507 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
509 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
511 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
512 if (current_state == MM_PLAYER_STATE_PAUSED)
513 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
520 case MMPLAYER_COMMAND_RESUME:
522 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
523 goto NOT_COMPLETED_SEEK;
525 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
527 if (pending_state == MM_PLAYER_STATE_NONE) {
528 if (current_state == MM_PLAYER_STATE_PLAYING)
530 else if (current_state != MM_PLAYER_STATE_PAUSED)
532 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
534 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
535 LOGD("player is going to paused state, just change the pending state as playing");
545 player->cmd = command;
547 return MM_ERROR_NONE;
550 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
551 MMPLAYER_STATE_GET_NAME(current_state), command);
552 return MM_ERROR_PLAYER_INVALID_STATE;
555 LOGW("not completed seek");
556 return MM_ERROR_PLAYER_DOING_SEEK;
559 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
560 return MM_ERROR_PLAYER_NO_OP;
563 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
564 return MM_ERROR_PLAYER_NO_OP;
567 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
569 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
570 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
573 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
576 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
577 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
579 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
580 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
583 LOGE("invalid mmplayer resource type %d", type);
584 return MM_ERROR_PLAYER_INTERNAL;
587 if (player->hw_resource[type] != NULL) {
588 LOGD("[%d type] resource was already acquired", type);
589 return MM_ERROR_NONE;
592 LOGD("mark for acquire [%d type] resource", type);
593 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
594 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
600 rm_ret = mm_resource_manager_commit(player->resource_manager);
601 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
602 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
603 return MM_ERROR_PLAYER_INTERNAL;
607 return MM_ERROR_NONE;
610 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
612 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
616 if (player->hw_resource[type] == NULL) {
617 LOGD("there is no acquired [%d type] resource", type);
618 return MM_ERROR_NONE;
621 LOGD("mark for release [%d type] resource", type);
622 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
623 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
624 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
625 return MM_ERROR_PLAYER_INTERNAL;
628 player->hw_resource[type] = NULL;
630 rm_ret = mm_resource_manager_commit(player->resource_manager);
631 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633 return MM_ERROR_PLAYER_INTERNAL;
637 return MM_ERROR_NONE;
641 __mmplayer_initialize_gapless_play(mmplayer_t *player)
647 player->smooth_streaming = FALSE;
648 player->videodec_linked = 0;
649 player->audiodec_linked = 0;
650 player->textsink_linked = 0;
651 player->is_external_subtitle_present = FALSE;
652 player->is_external_subtitle_added_now = FALSE;
653 player->not_supported_codec = MISSING_PLUGIN_NONE;
654 player->can_support_codec = FOUND_PLUGIN_NONE;
655 player->pending_seek.is_pending = false;
656 player->pending_seek.pos = 0;
657 player->msg_posted = FALSE;
658 player->has_many_types = FALSE;
659 player->no_more_pad = FALSE;
660 player->not_found_demuxer = 0;
661 player->seek_state = MMPLAYER_SEEK_NONE;
662 player->is_subtitle_force_drop = FALSE;
663 player->play_subtitle = FALSE;
664 player->adjust_subtitle_pos = 0;
666 player->total_bitrate = 0;
667 player->total_maximum_bitrate = 0;
669 _mmplayer_track_initialize(player);
670 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
672 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
673 player->bitrate[i] = 0;
674 player->maximum_bitrate[i] = 0;
677 if (player->v_stream_caps) {
678 gst_caps_unref(player->v_stream_caps);
679 player->v_stream_caps = NULL;
682 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
684 /* clean found audio decoders */
685 if (player->audio_decoders) {
686 GList *a_dec = player->audio_decoders;
687 for (; a_dec; a_dec = g_list_next(a_dec)) {
688 gchar *name = a_dec->data;
689 MMPLAYER_FREEIF(name);
691 g_list_free(player->audio_decoders);
692 player->audio_decoders = NULL;
695 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
701 __mmplayer_gapless_play_thread(gpointer data)
703 mmplayer_t *player = (mmplayer_t *)data;
704 mmplayer_gst_element_t *mainbin = NULL;
706 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
709 while (!player->gapless_play_thread_exit) {
710 LOGD("gapless play thread started. waiting for signal.");
711 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
713 LOGD("reconfigure pipeline for gapless play.");
715 if (player->gapless_play_thread_exit) {
716 if (player->gapless.reconfigure) {
717 player->gapless.reconfigure = false;
718 MMPLAYER_PLAYBACK_UNLOCK(player);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 MMHandleType attrs = 0;
1350 gint active_index = 0;
1353 MMPLAYER_RETURN_IF_FAIL(player);
1355 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1357 /* change track to active pad */
1358 active_index = player->selector[type].active_pad_index;
1359 if ((active_index != DEFAULT_TRACK) &&
1360 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1361 LOGW("failed to change %d type track to %d", type, active_index);
1362 player->selector[type].active_pad_index = DEFAULT_TRACK;
1366 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1367 attrs = MMPLAYER_GET_ATTRS(player);
1369 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1370 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1372 if (mm_attrs_commit_all(attrs))
1373 LOGW("failed to commit attrs.");
1375 LOGW("cannot get content attribute");
1384 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1389 if (!audio_selector) {
1390 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1392 /* in case the source is changed, output can be changed. */
1393 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1394 LOGD("remove previous audiobin if it exist");
1396 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1397 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1399 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1400 MMPLAYER_FREEIF(player->pipeline->audiobin);
1403 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1404 __mmplayer_pipeline_complete(NULL, player);
1409 /* apply the audio track information */
1410 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1412 /* create audio sink path */
1413 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1414 LOGE("failed to create audio sink path");
1423 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1426 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1428 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1429 LOGD("text path is not supproted");
1433 /* apply the text track information */
1434 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1436 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1437 player->has_closed_caption = TRUE;
1439 /* create text decode path */
1440 player->no_more_pad = TRUE;
1442 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1443 LOGE("failed to create text sink path");
1452 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1454 gint64 dur_bytes = 0L;
1457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1458 player->pipeline->mainbin && player->streamer, FALSE);
1460 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1461 LOGE("fail to get duration.");
1463 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1464 * use file information was already set on Q2 when it was created. */
1465 _mm_player_streaming_set_queue2(player->streamer,
1466 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1467 TRUE, /* use_buffering */
1468 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1469 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1476 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1478 mmplayer_t *player = NULL;
1479 GstElement *video_selector = NULL;
1480 GstElement *audio_selector = NULL;
1481 GstElement *text_selector = NULL;
1484 player = (mmplayer_t *)data;
1486 LOGD("no-more-pad signal handling");
1488 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1489 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1490 LOGW("player is shutting down");
1494 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1495 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1496 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1497 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1498 LOGE("failed to set queue2 buffering");
1503 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1504 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1505 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1507 if (!video_selector && !audio_selector && !text_selector) {
1508 LOGW("there is no selector");
1509 player->no_more_pad = TRUE;
1513 /* create video path followed by video-select */
1514 if (video_selector && !audio_selector && !text_selector)
1515 player->no_more_pad = TRUE;
1517 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1520 /* create audio path followed by audio-select */
1521 if (audio_selector && !text_selector)
1522 player->no_more_pad = TRUE;
1524 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1527 /* create text path followed by text-select */
1528 __mmplayer_create_text_sink_path(player, text_selector);
1531 if (player->gapless.reconfigure) {
1532 player->gapless.reconfigure = FALSE;
1533 MMPLAYER_PLAYBACK_UNLOCK(player);
1540 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1542 gboolean ret = FALSE;
1543 GstElement *pipeline = NULL;
1544 GstPad *sinkpad = NULL;
1547 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1550 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1552 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1554 LOGE("failed to get pad from sinkbin");
1560 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1561 LOGE("failed to link sinkbin for reusing");
1562 goto EXIT; /* exit either pass or fail */
1566 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1567 LOGE("failed to set state(READY) to sinkbin");
1572 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1573 LOGE("failed to add sinkbin to pipeline");
1578 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1579 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1584 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1585 LOGE("failed to set state(PAUSED) to sinkbin");
1594 gst_object_unref(GST_OBJECT(sinkpad));
1602 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1604 mmplayer_t *player = NULL;
1605 GstCaps *caps = NULL;
1606 gchar *caps_str = NULL;
1607 GstStructure *str = NULL;
1608 const gchar *name = NULL;
1609 GstElement *sinkbin = NULL;
1610 gboolean reusing = FALSE;
1611 gboolean caps_ret = TRUE;
1612 gchar *sink_pad_name = "sink";
1615 player = (mmplayer_t *)data;
1618 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1619 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1621 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1625 caps_str = gst_caps_to_string(caps);
1627 LOGD("detected mimetype : %s", name);
1629 if (strstr(name, "audio")) {
1630 if (player->pipeline->audiobin == NULL) {
1631 const gchar *audio_format = gst_structure_get_string(str, "format");
1633 LOGD("original audio format %s", audio_format);
1634 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1637 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1638 LOGE("failed to create audiobin. continuing without audio");
1642 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1643 LOGD("creating audiobin success");
1646 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1647 LOGD("reusing audiobin");
1648 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1650 } else if (strstr(name, "video")) {
1651 /* 1. zero copy is updated at _decode_pad_added()
1652 * 2. NULL surface type is handled in _decode_pad_added() */
1653 LOGD("zero copy %d", player->set_mode.video_zc);
1654 if (player->pipeline->videobin == NULL) {
1655 int surface_type = 0;
1656 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1657 LOGD("display_surface_type (%d)", surface_type);
1659 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1660 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1661 LOGE("failed to acquire video overlay resource");
1665 player->interrupted_by_resource = FALSE;
1667 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1668 LOGE("failed to create videobin. continuing without video");
1672 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1673 LOGD("creating videosink bin success");
1676 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1677 LOGD("re-using videobin");
1678 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1680 } else if (strstr(name, "text")) {
1681 if (player->pipeline->textbin == NULL) {
1682 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1683 LOGE("failed to create text sink bin. continuing without text");
1687 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1688 player->textsink_linked = 1;
1689 LOGD("creating textsink bin success");
1691 if (!player->textsink_linked) {
1692 LOGD("re-using textbin");
1694 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1695 player->textsink_linked = 1;
1697 /* linked textbin exist which means that the external subtitle path exist already */
1698 LOGW("ignoring internal subtutle since external subtitle is available");
1701 sink_pad_name = "text_sink";
1703 LOGW("unknown mime type %s, ignoring it", name);
1707 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1710 LOGD("[handle: %p] success to create and link sink bin", player);
1712 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1713 * streaming task. if the task blocked, then buffer will not flow to the next element
1714 *(autoplugging element). so this is special hack for streaming. please try to remove it
1716 /* dec stream count. we can remove fakesink if it's zero */
1717 if (player->num_dynamic_pad)
1718 player->num_dynamic_pad--;
1720 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1722 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1723 __mmplayer_pipeline_complete(NULL, player);
1727 MMPLAYER_FREEIF(caps_str);
1730 gst_caps_unref(caps);
1736 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1738 int required_angle = 0; /* Angle required for straight view */
1739 int rotation_angle = 0;
1741 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1742 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1744 /* Counter clockwise */
1745 switch (orientation) {
1750 required_angle = 270;
1753 required_angle = 180;
1756 required_angle = 90;
1760 rotation_angle = display_angle + required_angle;
1761 if (rotation_angle >= 360)
1762 rotation_angle -= 360;
1764 /* chech if supported or not */
1765 if (rotation_angle % 90) {
1766 LOGD("not supported rotation angle = %d", rotation_angle);
1770 switch (rotation_angle) {
1772 *value = MM_DISPLAY_ROTATION_NONE;
1775 *value = MM_DISPLAY_ROTATION_90;
1778 *value = MM_DISPLAY_ROTATION_180;
1781 *value = MM_DISPLAY_ROTATION_270;
1785 LOGD("setting rotation property value : %d", *value);
1791 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1793 /* check video sinkbin is created */
1794 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1796 player->pipeline->videobin &&
1797 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1798 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1799 MM_ERROR_PLAYER_NOT_INITIALIZED);
1801 return MM_ERROR_NONE;
1805 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1807 int display_rotation = 0;
1808 gchar *org_orient = NULL;
1809 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1812 LOGE("cannot get content attribute");
1813 return MM_ERROR_PLAYER_INTERNAL;
1816 if (display_angle) {
1817 /* update user roation */
1818 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1820 /* Counter clockwise */
1821 switch (display_rotation) {
1822 case MM_DISPLAY_ROTATION_NONE:
1825 case MM_DISPLAY_ROTATION_90:
1826 *display_angle = 90;
1828 case MM_DISPLAY_ROTATION_180:
1829 *display_angle = 180;
1831 case MM_DISPLAY_ROTATION_270:
1832 *display_angle = 270;
1835 LOGW("wrong angle type : %d", display_rotation);
1838 LOGD("check user angle: %d", *display_angle);
1842 /* Counter clockwise */
1843 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1846 if (!strcmp(org_orient, "rotate-90"))
1848 else if (!strcmp(org_orient, "rotate-180"))
1850 else if (!strcmp(org_orient, "rotate-270"))
1853 LOGD("original rotation is %s", org_orient);
1855 LOGD("content_video_orientation get fail");
1858 LOGD("check orientation: %d", *orientation);
1861 return MM_ERROR_NONE;
1865 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1867 int rotation_value = 0;
1868 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1869 int display_angle = 0;
1872 /* check video sinkbin is created */
1873 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1876 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1878 /* get rotation value to set */
1879 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1880 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1881 LOGD("set video param : rotate %d", rotation_value);
1885 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1887 MMHandleType attrs = 0;
1891 /* check video sinkbin is created */
1892 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1899 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1900 LOGD("set video param : visible %d", visible);
1904 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1906 MMHandleType attrs = 0;
1907 int display_method = 0;
1910 /* check video sinkbin is created */
1911 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1914 attrs = MMPLAYER_GET_ATTRS(player);
1915 MMPLAYER_RETURN_IF_FAIL(attrs);
1917 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1918 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1919 LOGD("set video param : method %d", display_method);
1923 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1925 MMHandleType attrs = 0;
1926 void *handle = NULL;
1929 /* check video sinkbin is created */
1930 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1931 LOGW("There is no video sink");
1935 attrs = MMPLAYER_GET_ATTRS(player);
1936 MMPLAYER_RETURN_IF_FAIL(attrs);
1937 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1939 gst_video_overlay_set_video_roi_area(
1940 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1941 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1942 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1943 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1948 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1950 MMHandleType attrs = 0;
1951 void *handle = NULL;
1955 int win_roi_width = 0;
1956 int win_roi_height = 0;
1959 /* check video sinkbin is created */
1960 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1961 LOGW("There is no video sink");
1965 attrs = MMPLAYER_GET_ATTRS(player);
1966 MMPLAYER_RETURN_IF_FAIL(attrs);
1968 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1971 /* It should be set after setting window */
1972 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1973 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1974 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1975 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1977 /* After setting window handle, set display roi area */
1978 gst_video_overlay_set_display_roi_area(
1979 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1980 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1981 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1982 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1987 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1989 MMHandleType attrs = 0;
1990 void *handle = NULL;
1992 /* check video sinkbin is created */
1993 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1996 attrs = MMPLAYER_GET_ATTRS(player);
1997 MMPLAYER_RETURN_IF_FAIL(attrs);
1999 /* common case if using overlay surface */
2000 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2003 /* default is using wl_surface_id */
2004 unsigned int wl_surface_id = 0;
2005 wl_surface_id = *(int *)handle;
2006 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2007 gst_video_overlay_set_wl_window_wl_surface_id(
2008 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2011 /* FIXIT : is it error case? */
2012 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2017 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2019 gboolean update_all_param = FALSE;
2022 /* check video sinkbin is created */
2023 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2024 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2026 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2027 LOGE("can not find tizenwlsink");
2028 return MM_ERROR_PLAYER_INTERNAL;
2031 LOGD("param_name : %s", param_name);
2032 if (!g_strcmp0(param_name, "update_all_param"))
2033 update_all_param = TRUE;
2035 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2036 __mmplayer_video_param_set_display_overlay(player);
2037 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2038 __mmplayer_video_param_set_display_method(player);
2039 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2040 __mmplayer_video_param_set_display_visible(player);
2041 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2042 __mmplayer_video_param_set_display_rotation(player);
2043 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2044 __mmplayer_video_param_set_roi_area(player);
2045 if (update_all_param)
2046 __mmplayer_video_param_set_video_roi_area(player);
2048 return MM_ERROR_NONE;
2052 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2054 MMHandleType attrs = 0;
2055 int surface_type = 0;
2056 int ret = MM_ERROR_NONE;
2060 /* check video sinkbin is created */
2061 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2062 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2064 attrs = MMPLAYER_GET_ATTRS(player);
2066 LOGE("cannot get content attribute");
2067 return MM_ERROR_PLAYER_INTERNAL;
2069 LOGD("param_name : %s", param_name);
2071 /* update display surface */
2072 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2073 LOGD("check display surface type attribute: %d", surface_type);
2075 /* configuring display */
2076 switch (surface_type) {
2077 case MM_DISPLAY_SURFACE_OVERLAY:
2079 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2080 if (ret != MM_ERROR_NONE)
2088 return MM_ERROR_NONE;
2092 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2094 gboolean disable_overlay = FALSE;
2095 mmplayer_t *player = (mmplayer_t *)hplayer;
2098 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2099 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2100 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2101 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2103 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2104 LOGW("Display control is not supported");
2105 return MM_ERROR_PLAYER_INTERNAL;
2108 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2110 if (audio_only == (bool)disable_overlay) {
2111 LOGE("It's the same with current setting: (%d)", audio_only);
2112 return MM_ERROR_NONE;
2116 LOGE("disable overlay");
2117 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2119 /* release overlay resource */
2120 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2121 LOGE("failed to release overlay resource");
2125 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2126 LOGE("failed to acquire video overlay resource");
2129 player->interrupted_by_resource = FALSE;
2131 LOGD("enable overlay");
2132 __mmplayer_video_param_set_display_overlay(player);
2133 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2138 return MM_ERROR_NONE;
2142 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2144 mmplayer_t *player = (mmplayer_t *)hplayer;
2145 gboolean disable_overlay = FALSE;
2149 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2150 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2151 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2152 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2153 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2155 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2156 LOGW("Display control is not supported");
2157 return MM_ERROR_PLAYER_INTERNAL;
2160 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2162 *paudio_only = (bool)disable_overlay;
2164 LOGD("audio_only : %d", *paudio_only);
2168 return MM_ERROR_NONE;
2172 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2174 GList *bucket = element_bucket;
2175 mmplayer_gst_element_t *element = NULL;
2176 mmplayer_gst_element_t *prv_element = NULL;
2177 GstElement *tee_element = NULL;
2178 gint successful_link_count = 0;
2182 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2184 prv_element = (mmplayer_gst_element_t *)bucket->data;
2185 bucket = bucket->next;
2187 for (; bucket; bucket = bucket->next) {
2188 element = (mmplayer_gst_element_t *)bucket->data;
2190 if (element && element->gst) {
2191 if (prv_element && prv_element->gst) {
2192 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2194 prv_element->gst = tee_element;
2196 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2197 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2198 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2202 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2203 LOGD("linking [%s] to [%s] success",
2204 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2205 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2206 successful_link_count++;
2207 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2208 LOGD("keep audio-tee element for next audio pipeline branch");
2209 tee_element = prv_element->gst;
2212 LOGD("linking [%s] to [%s] failed",
2213 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2214 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2220 prv_element = element;
2225 return successful_link_count;
2229 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2231 GList *bucket = element_bucket;
2232 mmplayer_gst_element_t *element = NULL;
2233 int successful_add_count = 0;
2237 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2238 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2240 for (; bucket; bucket = bucket->next) {
2241 element = (mmplayer_gst_element_t *)bucket->data;
2243 if (element && element->gst) {
2244 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2245 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2246 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2247 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2250 successful_add_count++;
2256 return successful_add_count;
2260 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2262 mmplayer_t *player = (mmplayer_t *)data;
2263 GstCaps *caps = NULL;
2264 GstStructure *str = NULL;
2266 gboolean caps_ret = TRUE;
2270 MMPLAYER_RETURN_IF_FAIL(pad);
2271 MMPLAYER_RETURN_IF_FAIL(unused);
2272 MMPLAYER_RETURN_IF_FAIL(data);
2274 caps = gst_pad_get_current_caps(pad);
2278 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2282 LOGD("name = %s", name);
2284 if (strstr(name, "audio")) {
2285 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2287 if (player->audio_stream_changed_cb) {
2288 LOGE("call the audio stream changed cb");
2289 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2291 } else if (strstr(name, "video")) {
2292 if ((name = gst_structure_get_string(str, "format")))
2293 player->set_mode.video_zc = name[0] == 'S';
2295 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2296 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2298 LOGW("invalid caps info");
2303 gst_caps_unref(caps);
2311 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2316 MMPLAYER_RETURN_IF_FAIL(player);
2318 if (player->audio_stream_buff_list) {
2319 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2320 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2323 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2324 __mmplayer_audio_stream_send_data(player, tmp);
2326 MMPLAYER_FREEIF(tmp->pcm_data);
2327 MMPLAYER_FREEIF(tmp);
2330 g_list_free(player->audio_stream_buff_list);
2331 player->audio_stream_buff_list = NULL;
2338 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2340 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2343 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2345 audio_stream.bitrate = a_buffer->bitrate;
2346 audio_stream.channel = a_buffer->channel;
2347 audio_stream.depth = a_buffer->depth;
2348 audio_stream.is_little_endian = a_buffer->is_little_endian;
2349 audio_stream.channel_mask = a_buffer->channel_mask;
2350 audio_stream.data_size = a_buffer->data_size;
2351 audio_stream.data = a_buffer->pcm_data;
2352 audio_stream.pcm_format = a_buffer->pcm_format;
2354 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2356 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2362 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2364 mmplayer_t *player = (mmplayer_t *)data;
2365 const gchar *pcm_format = NULL;
2369 gint endianness = 0;
2370 guint64 channel_mask = 0;
2371 void *a_data = NULL;
2373 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2374 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2378 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2380 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2381 a_data = mapinfo.data;
2382 a_size = mapinfo.size;
2384 GstCaps *caps = gst_pad_get_current_caps(pad);
2385 GstStructure *structure = gst_caps_get_structure(caps, 0);
2387 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2389 pcm_format = gst_structure_get_string(structure, "format");
2390 gst_structure_get_int(structure, "rate", &rate);
2391 gst_structure_get_int(structure, "channels", &channel);
2392 gst_structure_get_int(structure, "depth", &depth);
2393 gst_structure_get_int(structure, "endianness", &endianness);
2394 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2395 gst_caps_unref(GST_CAPS(caps));
2397 /* In case of the sync is false, use buffer list. *
2398 * The num of buffer list depends on the num of audio channels */
2399 if (player->audio_stream_buff_list) {
2400 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2401 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2403 if (channel_mask == tmp->channel_mask) {
2405 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2407 if (tmp->data_size + a_size < tmp->buff_size) {
2408 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2409 tmp->data_size += a_size;
2411 /* send data to client */
2412 __mmplayer_audio_stream_send_data(player, tmp);
2414 if (a_size > tmp->buff_size) {
2415 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2416 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2417 if (tmp->pcm_data == NULL) {
2418 LOGE("failed to realloc data.");
2421 tmp->buff_size = a_size;
2423 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2424 memcpy(tmp->pcm_data, a_data, a_size);
2425 tmp->data_size = a_size;
2430 LOGE("data is empty in list.");
2436 /* create new audio stream data for newly found audio channel */
2437 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2438 if (a_buffer == NULL) {
2439 LOGE("failed to alloc data.");
2442 a_buffer->bitrate = rate;
2443 a_buffer->channel = channel;
2444 a_buffer->depth = depth;
2445 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2446 a_buffer->channel_mask = channel_mask;
2447 a_buffer->data_size = a_size;
2448 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2450 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2451 /* If sync is FALSE, use buffer list to reduce the IPC. */
2452 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2453 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2454 if (a_buffer->pcm_data == NULL) {
2455 LOGE("failed to alloc data.");
2456 MMPLAYER_FREEIF(a_buffer);
2459 memcpy(a_buffer->pcm_data, a_data, a_size);
2461 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2463 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2465 /* If sync is TRUE, send data directly. */
2466 a_buffer->pcm_data = a_data;
2467 __mmplayer_audio_stream_send_data(player, a_buffer);
2468 MMPLAYER_FREEIF(a_buffer);
2472 gst_buffer_unmap(buffer, &mapinfo);
2477 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2479 mmplayer_t *player = (mmplayer_t *)data;
2480 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2481 GstPad *sinkpad = NULL;
2482 GstElement *queue = NULL, *sink = NULL;
2485 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2487 queue = gst_element_factory_make("queue", NULL);
2488 if (queue == NULL) {
2489 LOGD("fail make queue");
2493 sink = gst_element_factory_make("fakesink", NULL);
2495 LOGD("fail make fakesink");
2499 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2501 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2502 LOGW("failed to link queue & sink");
2506 sinkpad = gst_element_get_static_pad(queue, "sink");
2508 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2509 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2513 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2515 gst_object_unref(sinkpad);
2516 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2517 g_object_set(sink, "sync", TRUE, NULL);
2518 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2520 /* keep the first sink reference only */
2521 if (!audiobin[MMPLAYER_A_SINK].gst) {
2522 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2523 audiobin[MMPLAYER_A_SINK].gst = sink;
2526 gst_element_set_state(sink, GST_STATE_PAUSED);
2527 gst_element_set_state(queue, GST_STATE_PAUSED);
2529 _mmplayer_add_signal_connection(player,
2531 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2533 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2536 __mmplayer_add_sink(player, sink);
2542 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2544 gst_object_unref(GST_OBJECT(queue));
2548 gst_object_unref(GST_OBJECT(sink));
2552 gst_object_unref(GST_OBJECT(sinkpad));
2560 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2562 #define MAX_PROPS_LEN 128
2563 mmplayer_gst_element_t *audiobin = NULL;
2564 gint latency_mode = 0;
2565 gchar *stream_type = NULL;
2566 gchar *latency = NULL;
2568 gchar stream_props[MAX_PROPS_LEN] = {0,};
2569 GstStructure *props = NULL;
2572 * It should be set after player creation through attribute.
2573 * But, it can not be changed during playing.
2576 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2578 audiobin = player->pipeline->audiobin;
2580 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2581 if (player->sound.mute) {
2582 LOGD("mute enabled");
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2586 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2587 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2590 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2592 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2593 stream_type, stream_id, player->client_pid);
2595 props = gst_structure_from_string(stream_props, NULL);
2596 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2597 LOGI("props result[%s].", stream_props);
2598 gst_structure_free(props);
2600 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2602 switch (latency_mode) {
2603 case AUDIO_LATENCY_MODE_LOW:
2604 latency = g_strndup("low", 3);
2606 case AUDIO_LATENCY_MODE_MID:
2607 latency = g_strndup("mid", 3);
2609 case AUDIO_LATENCY_MODE_HIGH:
2610 latency = g_strndup("high", 4);
2614 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2616 LOGD("audiosink property - latency=%s", latency);
2618 MMPLAYER_FREEIF(latency);
2624 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2626 mmplayer_gst_element_t *audiobin = NULL;
2629 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2631 audiobin = player->pipeline->audiobin;
2633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2634 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2637 if (player->video360_yaw_radians <= M_PI &&
2638 player->video360_yaw_radians >= -M_PI &&
2639 player->video360_pitch_radians <= M_PI_2 &&
2640 player->video360_pitch_radians >= -M_PI_2) {
2641 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2642 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2643 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2644 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2645 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2646 "source-orientation-y", player->video360_metadata.init_view_heading,
2647 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2654 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2656 mmplayer_gst_element_t *audiobin = NULL;
2657 GstPad *sink_pad = NULL;
2658 GstCaps *acaps = NULL;
2660 int pitch_control = 0;
2661 double pitch_value = 1.0;
2664 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2665 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2667 audiobin = player->pipeline->audiobin;
2669 LOGD("make element for normal audio playback");
2671 /* audio bin structure for playback. {} means optional.
2672 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2674 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2675 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2678 /* for pitch control */
2679 mm_attrs_multiple_get(player->attrs, NULL,
2680 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2681 MM_PLAYER_PITCH_VALUE, &pitch_value,
2684 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2685 if (pitch_control && (player->videodec_linked == 0)) {
2686 GstElementFactory *factory;
2688 factory = gst_element_factory_find("pitch");
2690 gst_object_unref(factory);
2693 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2697 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2699 LOGW("there is no pitch element");
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2706 /* replaygain volume */
2707 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2708 if (player->sound.rg_enable)
2709 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2716 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2717 /* currently, only openalsink uses volume element */
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);
2727 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2729 /* audio effect element. if audio effect is enabled */
2730 if ((strcmp(player->ini.audioeffect_element, ""))
2732 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2735 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2737 if ((!player->bypass_audio_effect)
2738 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2739 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2740 if (!_mmplayer_audio_effect_custom_apply(player))
2741 LOGI("apply audio effect(custom) setting success");
2745 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2746 && (player->set_mode.rich_audio)) {
2747 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2751 /* create audio sink */
2752 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2753 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2754 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2756 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2757 if (player->is_360_feature_enabled &&
2758 player->is_content_spherical &&
2760 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2761 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2762 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2764 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2766 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2769 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2770 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2771 gst_caps_unref(acaps);
2773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2775 player->is_openal_plugin_used = TRUE;
2777 if (player->is_360_feature_enabled && player->is_content_spherical)
2778 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2782 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2783 (player->videodec_linked && player->ini.use_system_clock)) {
2784 LOGD("system clock will be used.");
2785 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2788 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2789 __mmplayer_gst_set_pulsesink_property(player);
2790 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2791 __mmplayer_gst_set_openalsink_property(player);
2794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2795 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2797 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2798 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2799 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2800 gst_object_unref(GST_OBJECT(sink_pad));
2802 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2805 return MM_ERROR_NONE;
2807 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2809 return MM_ERROR_PLAYER_INTERNAL;
2813 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2815 mmplayer_gst_element_t *audiobin = NULL;
2816 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2818 gchar *dst_format = NULL;
2820 int dst_samplerate = 0;
2821 int dst_channels = 0;
2822 GstCaps *caps = NULL;
2823 char *caps_str = NULL;
2826 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2827 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2829 audiobin = player->pipeline->audiobin;
2831 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2833 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2835 [case 1] extract interleave audio pcm without playback
2836 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2837 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2839 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2841 [case 2] deinterleave for each channel without playback
2842 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2843 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2845 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2846 - fakesink (sync or not)
2849 [case 3] [case 1(sync only)] + playback
2850 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2852 * src - ... - tee - queue1 - playback path
2853 - queue2 - [case1 pipeline with sync]
2855 [case 4] [case 2(sync only)] + playback
2856 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2858 * src - ... - tee - queue1 - playback path
2859 - queue2 - [case2 pipeline with sync]
2863 /* 1. create tee and playback path
2864 'tee' should be added at first to copy the decoded stream
2866 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2867 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2868 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2870 /* tee - path 1 : for playback path */
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2872 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2874 /* tee - path 2 : for extract path */
2875 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2876 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2879 /* if there is tee, 'tee - path 2' is linked here */
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2884 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2886 /* 2. decide the extract pcm format */
2887 mm_attrs_multiple_get(player->attrs, NULL,
2888 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2889 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2890 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2893 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2894 dst_format, dst_len, dst_samplerate, dst_channels);
2896 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2897 mm_attrs_multiple_get(player->attrs, NULL,
2898 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2899 "content_audio_samplerate", &dst_samplerate,
2900 "content_audio_channels", &dst_channels,
2903 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2904 dst_format, dst_len, dst_samplerate, dst_channels);
2906 /* If there is no enough information, set it to platform default value. */
2907 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2908 LOGD("set platform default format");
2909 dst_format = DEFAULT_PCM_OUT_FORMAT;
2911 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2912 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2915 /* 3. create capsfilter */
2916 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2917 caps = gst_caps_new_simple("audio/x-raw",
2918 "format", G_TYPE_STRING, dst_format,
2919 "rate", G_TYPE_INT, dst_samplerate,
2920 "channels", G_TYPE_INT, dst_channels,
2923 caps_str = gst_caps_to_string(caps);
2924 LOGD("new caps : %s", caps_str);
2926 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2929 gst_caps_unref(caps);
2930 MMPLAYER_FREEIF(caps_str);
2932 /* 4-1. create deinterleave to extract pcm for each channel */
2933 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2934 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2935 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2937 /* audiosink will be added after getting signal for each channel */
2938 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2939 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2941 /* 4-2. create fakesink to extract interlevaed pcm */
2942 LOGD("add audio fakesink for interleaved audio");
2943 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2944 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2945 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2946 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2948 _mmplayer_add_signal_connection(player,
2949 G_OBJECT(audiobin[extract_sink_id].gst),
2950 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2952 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2955 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2959 return MM_ERROR_NONE;
2961 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2963 return MM_ERROR_PLAYER_INTERNAL;
2967 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2969 int ret = MM_ERROR_NONE;
2970 mmplayer_gst_element_t *audiobin = NULL;
2971 GList *element_bucket = NULL;
2974 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2975 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2977 audiobin = player->pipeline->audiobin;
2979 if (player->build_audio_offload) { /* skip all the audio filters */
2980 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2982 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2983 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2984 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2986 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2990 /* FIXME: need to mention the supportable condition at API reference */
2991 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2992 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2994 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2996 if (ret != MM_ERROR_NONE)
2999 LOGD("success to make audio bin element");
3000 *bucket = element_bucket;
3003 return MM_ERROR_NONE;
3006 LOGE("failed to make audio bin element");
3007 g_list_free(element_bucket);
3011 return MM_ERROR_PLAYER_INTERNAL;
3015 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3017 mmplayer_gst_element_t *first_element = NULL;
3018 mmplayer_gst_element_t *audiobin = NULL;
3020 GstPad *ghostpad = NULL;
3021 GList *element_bucket = NULL;
3025 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3028 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3030 LOGE("failed to allocate memory for audiobin");
3031 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3035 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3036 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3037 if (!audiobin[MMPLAYER_A_BIN].gst) {
3038 LOGE("failed to create audiobin");
3043 player->pipeline->audiobin = audiobin;
3045 /* create audio filters and audiosink */
3046 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3049 /* adding created elements to bin */
3050 LOGD("adding created elements to bin");
3051 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3054 /* linking elements in the bucket by added order. */
3055 LOGD("Linking elements in the bucket by added order.");
3056 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3059 /* get first element's sinkpad for creating ghostpad */
3060 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3061 if (!first_element) {
3062 LOGE("failed to get first elem");
3066 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3068 LOGE("failed to get pad from first element of audiobin");
3072 ghostpad = gst_ghost_pad_new("sink", pad);
3074 LOGE("failed to create ghostpad");
3078 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3079 LOGE("failed to add ghostpad to audiobin");
3083 gst_object_unref(pad);
3085 g_list_free(element_bucket);
3088 return MM_ERROR_NONE;
3091 LOGD("ERROR : releasing audiobin");
3094 gst_object_unref(GST_OBJECT(pad));
3097 gst_object_unref(GST_OBJECT(ghostpad));
3100 g_list_free(element_bucket);
3102 /* release element which are not added to bin */
3103 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3104 /* NOTE : skip bin */
3105 if (audiobin[i].gst) {
3106 GstObject *parent = NULL;
3107 parent = gst_element_get_parent(audiobin[i].gst);
3110 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3111 audiobin[i].gst = NULL;
3113 gst_object_unref(GST_OBJECT(parent));
3117 /* release audiobin with it's childs */
3118 if (audiobin[MMPLAYER_A_BIN].gst)
3119 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3121 MMPLAYER_FREEIF(audiobin);
3123 player->pipeline->audiobin = NULL;
3125 return MM_ERROR_PLAYER_INTERNAL;
3129 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3131 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3135 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3137 int ret = MM_ERROR_NONE;
3139 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3140 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3142 MMPLAYER_VIDEO_BO_LOCK(player);
3144 if (player->video_bo_list) {
3145 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3146 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3147 if (tmp && tmp->bo == bo) {
3149 LOGD("release bo %p", bo);
3150 tbm_bo_unref(tmp->bo);
3151 MMPLAYER_VIDEO_BO_UNLOCK(player);
3152 MMPLAYER_VIDEO_BO_SIGNAL(player);
3157 /* hw codec is running or the list was reset for DRC. */
3158 LOGW("there is no bo list.");
3160 MMPLAYER_VIDEO_BO_UNLOCK(player);
3162 LOGW("failed to find bo %p", bo);
3167 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3172 MMPLAYER_RETURN_IF_FAIL(player);
3174 MMPLAYER_VIDEO_BO_LOCK(player);
3175 if (player->video_bo_list) {
3176 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3177 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3178 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3181 tbm_bo_unref(tmp->bo);
3185 g_list_free(player->video_bo_list);
3186 player->video_bo_list = NULL;
3188 player->video_bo_size = 0;
3189 MMPLAYER_VIDEO_BO_UNLOCK(player);
3196 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3199 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3200 gboolean ret = TRUE;
3202 /* check DRC, if it is, destroy the prev bo list to create again */
3203 if (player->video_bo_size != size) {
3204 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3205 __mmplayer_video_stream_destroy_bo_list(player);
3206 player->video_bo_size = size;
3209 MMPLAYER_VIDEO_BO_LOCK(player);
3211 if ((!player->video_bo_list) ||
3212 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3214 /* create bo list */
3216 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3218 if (player->video_bo_list) {
3219 /* if bo list did not created all, try it again. */
3220 idx = g_list_length(player->video_bo_list);
3221 LOGD("bo list exist(len: %d)", idx);
3224 for (; idx < player->ini.num_of_video_bo; idx++) {
3225 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3227 LOGE("Fail to alloc bo_info.");
3230 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3232 LOGE("Fail to tbm_bo_alloc.");
3233 MMPLAYER_FREEIF(bo_info);
3236 bo_info->used = FALSE;
3237 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3240 /* update video num buffers */
3241 LOGD("video_num_buffers : %d", idx);
3242 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3243 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3246 MMPLAYER_VIDEO_BO_UNLOCK(player);
3252 /* get bo from list*/
3253 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3254 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3255 if (tmp && (tmp->used == FALSE)) {
3256 LOGD("found bo %p to use", tmp->bo);
3258 MMPLAYER_VIDEO_BO_UNLOCK(player);
3259 return tbm_bo_ref(tmp->bo);
3263 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3264 MMPLAYER_VIDEO_BO_UNLOCK(player);
3268 if (player->ini.video_bo_timeout <= 0) {
3269 MMPLAYER_VIDEO_BO_WAIT(player);
3271 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3272 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3279 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3281 mmplayer_t *player = (mmplayer_t *)data;
3283 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3285 /* send prerolled pkt */
3286 player->video_stream_prerolled = false;
3288 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3290 /* not to send prerolled pkt again */
3291 player->video_stream_prerolled = true;
3295 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3297 mmplayer_t *player = (mmplayer_t *)data;
3298 mmplayer_video_decoded_data_info_t *stream = NULL;
3299 GstMemory *mem = NULL;
3302 MMPLAYER_RETURN_IF_FAIL(player);
3303 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3305 if (player->video_stream_prerolled) {
3306 player->video_stream_prerolled = false;
3307 LOGD("skip the prerolled pkt not to send it again");
3311 /* clear stream data structure */
3312 stream = __mmplayer_create_stream_from_pad(pad);
3314 LOGE("failed to alloc stream");
3318 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3320 /* set size and timestamp */
3321 mem = gst_buffer_peek_memory(buffer, 0);
3322 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3323 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3325 /* check zero-copy */
3326 if (player->set_mode.video_zc &&
3327 player->set_mode.video_export &&
3328 gst_is_tizen_memory(mem)) {
3329 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3330 stream->internal_buffer = gst_buffer_ref(buffer);
3331 } else { /* sw codec */
3332 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3335 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3339 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3340 LOGE("failed to send video decoded data.");
3347 LOGE("release video stream resource.");
3348 if (gst_is_tizen_memory(mem)) {
3350 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3352 tbm_bo_unref(stream->bo[i]);
3355 /* unref gst buffer */
3356 if (stream->internal_buffer)
3357 gst_buffer_unref(stream->internal_buffer);
3360 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3362 MMPLAYER_FREEIF(stream);
3367 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3369 mmplayer_gst_element_t *videobin = NULL;
3372 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3374 videobin = player->pipeline->videobin;
3376 /* Set spatial media metadata and/or user settings to the element.
3378 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3379 "projection-type", player->video360_metadata.projection_type, NULL);
3381 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3382 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3384 if (player->video360_metadata.full_pano_width_pixels &&
3385 player->video360_metadata.full_pano_height_pixels &&
3386 player->video360_metadata.cropped_area_image_width &&
3387 player->video360_metadata.cropped_area_image_height) {
3388 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3389 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3390 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3391 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3392 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3393 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3394 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3398 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3399 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400 "horizontal-fov", player->video360_horizontal_fov,
3401 "vertical-fov", player->video360_vertical_fov, NULL);
3404 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3405 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3406 "zoom", 1.0f / player->video360_zoom, NULL);
3409 if (player->video360_yaw_radians <= M_PI &&
3410 player->video360_yaw_radians >= -M_PI &&
3411 player->video360_pitch_radians <= M_PI_2 &&
3412 player->video360_pitch_radians >= -M_PI_2) {
3413 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3414 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3415 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3416 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3417 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3418 "pose-yaw", player->video360_metadata.init_view_heading,
3419 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3422 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3423 "passthrough", !player->is_video360_enabled, NULL);
3430 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3432 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3433 GList *element_bucket = NULL;
3436 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3438 /* create video360 filter */
3439 if (player->is_360_feature_enabled && player->is_content_spherical) {
3440 LOGD("create video360 element");
3441 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3442 __mmplayer_gst_set_video360_property(player);
3446 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3447 LOGD("skip creating the videoconv and rotator");
3448 return MM_ERROR_NONE;
3451 /* in case of sw codec & overlay surface type, except 360 playback.
3452 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3453 LOGD("create video converter: %s", video_csc);
3454 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3457 *bucket = element_bucket;
3459 return MM_ERROR_NONE;
3461 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3462 g_list_free(element_bucket);
3466 return MM_ERROR_PLAYER_INTERNAL;
3470 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3472 gchar *factory_name = NULL;
3474 switch (surface_type) {
3475 case MM_DISPLAY_SURFACE_OVERLAY:
3476 if (strlen(player->ini.videosink_element_overlay) > 0)
3477 factory_name = player->ini.videosink_element_overlay;
3479 case MM_DISPLAY_SURFACE_REMOTE:
3480 case MM_DISPLAY_SURFACE_NULL:
3481 if (strlen(player->ini.videosink_element_fake) > 0)
3482 factory_name = player->ini.videosink_element_fake;
3485 LOGE("unidentified surface type");
3489 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3490 return factory_name;
3494 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3496 gchar *factory_name = NULL;
3497 mmplayer_gst_element_t *videobin = NULL;
3502 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3504 videobin = player->pipeline->videobin;
3505 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3507 attrs = MMPLAYER_GET_ATTRS(player);
3509 LOGE("cannot get content attribute");
3510 return MM_ERROR_PLAYER_INTERNAL;
3513 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3514 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3515 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3517 /* support shard memory with S/W codec on HawkP */
3518 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3519 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3520 "use-tbm", use_tbm, NULL);
3524 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3525 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3528 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3530 LOGD("disable last-sample");
3531 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3534 if (player->set_mode.video_export) {
3536 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3537 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3538 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3540 _mmplayer_add_signal_connection(player,
3541 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3542 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3544 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3547 _mmplayer_add_signal_connection(player,
3548 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3549 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3551 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3555 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3556 return MM_ERROR_PLAYER_INTERNAL;
3558 if (videobin[MMPLAYER_V_SINK].gst) {
3559 GstPad *sink_pad = NULL;
3560 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3562 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3563 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3564 gst_object_unref(GST_OBJECT(sink_pad));
3566 LOGE("failed to get sink pad from videosink");
3570 return MM_ERROR_NONE;
3575 * - video overlay surface(arm/x86) : tizenwlsink
3578 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3581 GList *element_bucket = NULL;
3582 mmplayer_gst_element_t *first_element = NULL;
3583 mmplayer_gst_element_t *videobin = NULL;
3584 gchar *videosink_factory_name = NULL;
3587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3590 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3592 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3594 player->pipeline->videobin = videobin;
3597 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3598 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3599 if (!videobin[MMPLAYER_V_BIN].gst) {
3600 LOGE("failed to create videobin");
3604 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3607 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3608 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3610 /* additional setting for sink plug-in */
3611 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3612 LOGE("failed to set video property");
3616 /* store it as it's sink element */
3617 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3619 /* adding created elements to bin */
3620 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3621 LOGE("failed to add elements");
3625 /* Linking elements in the bucket by added order */
3626 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3627 LOGE("failed to link elements");
3631 /* get first element's sinkpad for creating ghostpad */
3632 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3633 if (!first_element) {
3634 LOGE("failed to get first element from bucket");
3638 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3640 LOGE("failed to get pad from first element");
3644 /* create ghostpad */
3645 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3646 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3647 LOGE("failed to add ghostpad to videobin");
3650 gst_object_unref(pad);
3652 /* done. free allocated variables */
3653 g_list_free(element_bucket);
3657 return MM_ERROR_NONE;
3660 LOGE("ERROR : releasing videobin");
3661 g_list_free(element_bucket);
3664 gst_object_unref(GST_OBJECT(pad));
3666 /* release videobin with it's childs */
3667 if (videobin[MMPLAYER_V_BIN].gst)
3668 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3670 MMPLAYER_FREEIF(videobin);
3671 player->pipeline->videobin = NULL;
3673 return MM_ERROR_PLAYER_INTERNAL;
3677 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3679 GList *element_bucket = NULL;
3680 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3682 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3683 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3684 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3685 "signal-handoffs", FALSE,
3688 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3689 _mmplayer_add_signal_connection(player,
3690 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3691 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3693 G_CALLBACK(__mmplayer_update_subtitle),
3696 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3697 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3699 if (!player->play_subtitle) {
3700 LOGD("add textbin sink as sink element of whole pipeline.");
3701 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3704 /* adding created elements to bin */
3705 LOGD("adding created elements to bin");
3706 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3707 LOGE("failed to add elements");
3711 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3712 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3713 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3715 /* linking elements in the bucket by added order. */
3716 LOGD("Linking elements in the bucket by added order.");
3717 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3718 LOGE("failed to link elements");
3722 /* done. free allocated variables */
3723 g_list_free(element_bucket);
3725 if (textbin[MMPLAYER_T_QUEUE].gst) {
3727 GstPad *ghostpad = NULL;
3729 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3731 LOGE("failed to get sink pad of text queue");
3735 ghostpad = gst_ghost_pad_new("text_sink", pad);
3736 gst_object_unref(pad);
3739 LOGE("failed to create ghostpad of textbin");
3743 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3744 LOGE("failed to add ghostpad to textbin");
3745 gst_object_unref(ghostpad);
3750 return MM_ERROR_NONE;
3753 g_list_free(element_bucket);
3755 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3756 LOGE("remove textbin sink from sink list");
3757 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3760 /* release element at __mmplayer_gst_create_text_sink_bin */
3761 return MM_ERROR_PLAYER_INTERNAL;
3765 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3767 mmplayer_gst_element_t *textbin = NULL;
3768 GList *element_bucket = NULL;
3769 int surface_type = 0;
3774 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3777 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3779 LOGE("failed to allocate memory for textbin");
3780 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3784 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3785 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3786 if (!textbin[MMPLAYER_T_BIN].gst) {
3787 LOGE("failed to create textbin");
3792 player->pipeline->textbin = textbin;
3795 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3796 LOGD("surface type for subtitle : %d", surface_type);
3797 switch (surface_type) {
3798 case MM_DISPLAY_SURFACE_OVERLAY:
3799 case MM_DISPLAY_SURFACE_NULL:
3800 case MM_DISPLAY_SURFACE_REMOTE:
3801 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3802 LOGE("failed to make plain text elements");
3813 return MM_ERROR_NONE;
3817 LOGD("ERROR : releasing textbin");
3819 g_list_free(element_bucket);
3821 /* release signal */
3822 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3824 /* release element which are not added to bin */
3825 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3826 /* NOTE : skip bin */
3827 if (textbin[i].gst) {
3828 GstObject *parent = NULL;
3829 parent = gst_element_get_parent(textbin[i].gst);
3832 gst_object_unref(GST_OBJECT(textbin[i].gst));
3833 textbin[i].gst = NULL;
3835 gst_object_unref(GST_OBJECT(parent));
3840 /* release textbin with it's childs */
3841 if (textbin[MMPLAYER_T_BIN].gst)
3842 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3844 MMPLAYER_FREEIF(player->pipeline->textbin);
3845 player->pipeline->textbin = NULL;
3848 return MM_ERROR_PLAYER_INTERNAL;
3852 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3854 mmplayer_gst_element_t *mainbin = NULL;
3855 mmplayer_gst_element_t *textbin = NULL;
3856 MMHandleType attrs = 0;
3857 GstElement *subsrc = NULL;
3858 GstElement *subparse = NULL;
3859 gchar *subtitle_uri = NULL;
3860 const gchar *charset = NULL;
3866 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3868 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3870 mainbin = player->pipeline->mainbin;
3872 attrs = MMPLAYER_GET_ATTRS(player);
3874 LOGE("cannot get content attribute");
3875 return MM_ERROR_PLAYER_INTERNAL;
3878 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3879 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3880 LOGE("subtitle uri is not proper filepath.");
3881 return MM_ERROR_PLAYER_INVALID_URI;
3884 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3885 LOGE("failed to get storage info of subtitle path");
3886 return MM_ERROR_PLAYER_INVALID_URI;
3889 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3891 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3892 player->subtitle_language_list = NULL;
3893 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3895 /* create the subtitle source */
3896 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3898 LOGE("failed to create filesrc element");
3901 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3903 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3904 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3906 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3907 LOGW("failed to add queue");
3908 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3909 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3910 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3915 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3917 LOGE("failed to create subparse element");
3921 charset = _mmplayer_get_charset(subtitle_uri);
3923 LOGD("detected charset is %s", charset);
3924 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3927 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3928 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3930 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3931 LOGW("failed to add subparse");
3932 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3933 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3934 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3938 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3939 LOGW("failed to link subsrc and subparse");
3943 player->play_subtitle = TRUE;
3944 player->adjust_subtitle_pos = 0;
3946 LOGD("play subtitle using subtitle file");
3948 if (player->pipeline->textbin == NULL) {
3949 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3950 LOGE("failed to create text sink bin. continuing without text");
3954 textbin = player->pipeline->textbin;
3956 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3957 LOGW("failed to add textbin");
3959 /* release signal */
3960 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3962 /* release textbin with it's childs */
3963 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3964 MMPLAYER_FREEIF(player->pipeline->textbin);
3965 player->pipeline->textbin = textbin = NULL;
3969 LOGD("link text input selector and textbin ghost pad");
3971 player->textsink_linked = 1;
3972 player->external_text_idx = 0;
3973 LOGI("textsink is linked");
3975 textbin = player->pipeline->textbin;
3976 LOGD("text bin has been created. reuse it.");
3977 player->external_text_idx = 1;
3980 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3981 LOGW("failed to link subparse and textbin");
3985 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3987 LOGE("failed to get sink pad from textsink to probe data");
3991 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3992 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3994 gst_object_unref(pad);
3997 /* create dot. for debugging */
3998 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4001 return MM_ERROR_NONE;
4004 /* release text pipeline resource */
4005 player->textsink_linked = 0;
4007 /* release signal */
4008 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4010 if (player->pipeline->textbin) {
4011 LOGE("remove textbin");
4013 /* release textbin with it's childs */
4014 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4015 MMPLAYER_FREEIF(player->pipeline->textbin);
4016 player->pipeline->textbin = NULL;
4020 /* release subtitle elem */
4021 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4022 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4024 return MM_ERROR_PLAYER_INTERNAL;
4028 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4030 mmplayer_t *player = (mmplayer_t *)data;
4031 MMMessageParamType msg = {0, };
4032 GstClockTime duration = 0;
4033 gpointer text = NULL;
4034 guint text_size = 0;
4035 gboolean ret = TRUE;
4036 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4040 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4041 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4043 if (player->is_subtitle_force_drop) {
4044 LOGW("subtitle is dropped forcedly.");
4048 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4049 text = mapinfo.data;
4050 text_size = mapinfo.size;
4052 if (player->set_mode.subtitle_off) {
4053 LOGD("subtitle is OFF.");
4057 if (!text || (text_size == 0)) {
4058 LOGD("There is no subtitle to be displayed.");
4062 msg.data = (void *)text;
4064 duration = GST_BUFFER_DURATION(buffer);
4066 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4067 if (player->duration > GST_BUFFER_PTS(buffer))
4068 duration = player->duration - GST_BUFFER_PTS(buffer);
4071 LOGI("subtitle duration is invalid, subtitle duration change "
4072 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4074 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4076 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4078 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4079 gst_buffer_unmap(buffer, &mapinfo);
4086 static GstPadProbeReturn
4087 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4089 mmplayer_t *player = (mmplayer_t *)u_data;
4090 GstClockTime cur_timestamp = 0;
4091 gint64 adjusted_timestamp = 0;
4092 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4094 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4096 if (player->set_mode.subtitle_off) {
4097 LOGD("subtitle is OFF.");
4101 if (player->adjust_subtitle_pos == 0) {
4102 LOGD("nothing to do");
4106 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4107 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4109 if (adjusted_timestamp < 0) {
4110 LOGD("adjusted_timestamp under zero");
4115 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4116 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4117 GST_TIME_ARGS(cur_timestamp),
4118 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4120 return GST_PAD_PROBE_OK;
4124 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4128 /* check player and subtitlebin are created */
4129 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4130 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4132 if (position == 0) {
4133 LOGD("nothing to do");
4135 return MM_ERROR_NONE;
4138 /* check current postion */
4139 player->adjust_subtitle_pos = position;
4141 LOGD("save adjust_subtitle_pos in player");
4145 return MM_ERROR_NONE;
4149 * This function is to create audio or video pipeline for playing.
4151 * @param player [in] handle of player
4153 * @return This function returns zero on success.
4158 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4160 int ret = MM_ERROR_NONE;
4161 mmplayer_gst_element_t *mainbin = NULL;
4162 MMHandleType attrs = 0;
4165 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4167 /* get profile attribute */
4168 attrs = MMPLAYER_GET_ATTRS(player);
4170 LOGE("failed to get content attribute");
4174 /* create pipeline handles */
4175 if (player->pipeline) {
4176 LOGE("pipeline should be released before create new one");
4180 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4181 if (player->pipeline == NULL)
4184 /* create mainbin */
4185 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4186 if (mainbin == NULL)
4189 /* create pipeline */
4190 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4191 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4192 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4193 LOGE("failed to create pipeline");
4198 player->pipeline->mainbin = mainbin;
4200 /* create the source and decoder elements */
4201 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4202 ret = _mmplayer_gst_build_es_pipeline(player);
4204 ret = _mmplayer_gst_build_pipeline(player);
4206 if (ret != MM_ERROR_NONE) {
4207 LOGE("failed to create some elements");
4211 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4212 if (__mmplayer_check_subtitle(player)
4213 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4214 LOGE("failed to create text pipeline");
4217 ret = _mmplayer_gst_add_bus_watch(player);
4218 if (ret != MM_ERROR_NONE) {
4219 LOGE("failed to add bus watch");
4224 return MM_ERROR_NONE;
4227 __mmplayer_gst_destroy_pipeline(player);
4228 return MM_ERROR_PLAYER_INTERNAL;
4232 __mmplayer_reset_gapless_state(mmplayer_t *player)
4235 MMPLAYER_RETURN_IF_FAIL(player
4237 && player->pipeline->audiobin
4238 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4240 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4247 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4250 int ret = MM_ERROR_NONE;
4254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4256 /* cleanup stuffs */
4257 MMPLAYER_FREEIF(player->type);
4258 player->no_more_pad = FALSE;
4259 player->num_dynamic_pad = 0;
4260 player->demux_pad_index = 0;
4262 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4263 player->subtitle_language_list = NULL;
4264 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4266 __mmplayer_reset_gapless_state(player);
4268 if (player->streamer) {
4269 _mm_player_streaming_initialize(player->streamer, FALSE);
4270 _mm_player_streaming_destroy(player->streamer);
4271 player->streamer = NULL;
4274 /* cleanup unlinked mime type */
4275 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4276 MMPLAYER_FREEIF(player->unlinked_video_mime);
4277 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4279 /* cleanup running stuffs */
4280 _mmplayer_cancel_eos_timer(player);
4282 /* cleanup gst stuffs */
4283 if (player->pipeline) {
4284 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4285 GstTagList *tag_list = player->pipeline->tag_list;
4287 /* first we need to disconnect all signal hander */
4288 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4291 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4292 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4293 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4294 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4295 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4296 gst_object_unref(bus);
4298 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4299 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4300 if (ret != MM_ERROR_NONE) {
4301 LOGE("fail to change state to NULL");
4302 return MM_ERROR_PLAYER_INTERNAL;
4305 LOGW("succeeded in changing state to NULL");
4307 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4310 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4311 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4313 /* free avsysaudiosink
4314 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4315 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4317 MMPLAYER_FREEIF(audiobin);
4318 MMPLAYER_FREEIF(videobin);
4319 MMPLAYER_FREEIF(textbin);
4320 MMPLAYER_FREEIF(mainbin);
4324 gst_tag_list_unref(tag_list);
4326 MMPLAYER_FREEIF(player->pipeline);
4328 MMPLAYER_FREEIF(player->album_art);
4330 if (player->v_stream_caps) {
4331 gst_caps_unref(player->v_stream_caps);
4332 player->v_stream_caps = NULL;
4335 if (player->a_stream_caps) {
4336 gst_caps_unref(player->a_stream_caps);
4337 player->a_stream_caps = NULL;
4340 if (player->s_stream_caps) {
4341 gst_caps_unref(player->s_stream_caps);
4342 player->s_stream_caps = NULL;
4344 _mmplayer_track_destroy(player);
4346 if (player->sink_elements)
4347 g_list_free(player->sink_elements);
4348 player->sink_elements = NULL;
4350 if (player->bufmgr) {
4351 tbm_bufmgr_deinit(player->bufmgr);
4352 player->bufmgr = NULL;
4355 LOGW("finished destroy pipeline");
4363 __mmplayer_gst_realize(mmplayer_t *player)
4366 int ret = MM_ERROR_NONE;
4370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4372 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4374 ret = __mmplayer_gst_create_pipeline(player);
4376 LOGE("failed to create pipeline");
4380 /* set pipeline state to READY */
4381 /* NOTE : state change to READY must be performed sync. */
4382 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4383 ret = _mmplayer_gst_set_state(player,
4384 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4386 if (ret != MM_ERROR_NONE) {
4387 /* return error if failed to set state */
4388 LOGE("failed to set READY state");
4392 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4394 /* create dot before error-return. for debugging */
4395 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4403 __mmplayer_gst_unrealize(mmplayer_t *player)
4405 int ret = MM_ERROR_NONE;
4409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4411 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4412 MMPLAYER_PRINT_STATE(player);
4414 /* release miscellaneous information */
4415 __mmplayer_release_misc(player);
4417 /* destroy pipeline */
4418 ret = __mmplayer_gst_destroy_pipeline(player);
4419 if (ret != MM_ERROR_NONE) {
4420 LOGE("failed to destory pipeline");
4424 /* release miscellaneous information.
4425 these info needs to be released after pipeline is destroyed. */
4426 __mmplayer_release_misc_post(player);
4428 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4436 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4441 LOGW("set_message_callback is called with invalid player handle");
4442 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4445 player->msg_cb = callback;
4446 player->msg_cb_param = user_param;
4448 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4452 return MM_ERROR_NONE;
4456 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4458 int ret = MM_ERROR_NONE;
4463 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4464 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4465 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4467 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4469 if (strstr(uri, "es_buff://")) {
4470 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4471 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4472 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4473 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4475 tmp = g_ascii_strdown(uri, strlen(uri));
4476 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4477 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4479 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4481 } else if (strstr(uri, "mms://")) {
4482 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4483 } else if ((path = strstr(uri, "mem://"))) {
4484 ret = __mmplayer_set_mem_uri(data, path, param);
4486 ret = __mmplayer_set_file_uri(data, uri);
4489 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4490 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4491 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4492 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4494 /* dump parse result */
4495 SECURE_LOGW("incoming uri : %s", uri);
4496 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4497 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4505 __mmplayer_can_do_interrupt(mmplayer_t *player)
4507 if (!player || !player->pipeline || !player->attrs) {
4508 LOGW("not initialized");
4512 if (player->audio_decoded_cb) {
4513 LOGW("not support in pcm extraction mode");
4517 /* check if seeking */
4518 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4519 MMMessageParamType msg_param;
4520 memset(&msg_param, 0, sizeof(MMMessageParamType));
4521 msg_param.code = MM_ERROR_PLAYER_SEEK;
4522 player->seek_state = MMPLAYER_SEEK_NONE;
4523 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4527 /* check other thread */
4528 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4529 LOGW("locked already, cmd state : %d", player->cmd);
4531 /* check application command */
4532 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4533 LOGW("playing.. should wait cmd lock then, will be interrupted");
4535 /* lock will be released at mrp_resource_release_cb() */
4536 MMPLAYER_CMD_LOCK(player);
4539 LOGW("nothing to do");
4542 LOGW("can interrupt immediately");
4546 FAILED: /* with CMD UNLOCKED */
4549 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4554 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4557 mmplayer_t *player = NULL;
4558 MMMessageParamType msg = {0, };
4560 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4565 LOGE("user_data is null");
4568 player = (mmplayer_t *)user_data;
4570 if (!__mmplayer_can_do_interrupt(player)) {
4571 LOGW("no need to interrupt, so leave");
4572 /* FIXME: there is no way to avoid releasing resource. */
4576 player->interrupted_by_resource = TRUE;
4578 /* get last play position */
4579 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4580 msg.union_type = MM_MSG_UNION_TIME;
4581 msg.time.elapsed = pos;
4582 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4584 LOGW("failed to get play position.");
4587 LOGD("video resource conflict so, resource will be freed by unrealizing");
4588 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4589 LOGE("failed to unrealize");
4591 /* lock is called in __mmplayer_can_do_interrupt() */
4592 MMPLAYER_CMD_UNLOCK(player);
4594 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4595 player->hw_resource[res_idx] = NULL;
4599 return TRUE; /* release all the resources */
4603 __mmplayer_initialize_video_roi(mmplayer_t *player)
4605 player->video_roi.scale_x = 0.0;
4606 player->video_roi.scale_y = 0.0;
4607 player->video_roi.scale_width = 1.0;
4608 player->video_roi.scale_height = 1.0;
4612 _mmplayer_create_player(MMHandleType handle)
4614 int ret = MM_ERROR_PLAYER_INTERNAL;
4615 bool enabled = false;
4617 mmplayer_t *player = MM_PLAYER_CAST(handle);
4621 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4623 /* initialize player state */
4624 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4625 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4626 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4627 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4629 /* check current state */
4630 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4632 /* construct attributes */
4633 player->attrs = _mmplayer_construct_attribute(handle);
4635 if (!player->attrs) {
4636 LOGE("Failed to construct attributes");
4640 /* initialize gstreamer with configured parameter */
4641 if (!__mmplayer_init_gstreamer(player)) {
4642 LOGE("Initializing gstreamer failed");
4643 _mmplayer_deconstruct_attribute(handle);
4647 /* create lock. note that g_tread_init() has already called in gst_init() */
4648 g_mutex_init(&player->fsink_lock);
4650 /* create update tag lock */
4651 g_mutex_init(&player->update_tag_lock);
4653 /* create gapless play mutex */
4654 g_mutex_init(&player->gapless_play_thread_mutex);
4656 /* create gapless play cond */
4657 g_cond_init(&player->gapless_play_thread_cond);
4659 /* create gapless play thread */
4660 player->gapless_play_thread =
4661 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4662 if (!player->gapless_play_thread) {
4663 LOGE("failed to create gapless play thread");
4664 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4665 g_mutex_clear(&player->gapless_play_thread_mutex);
4666 g_cond_clear(&player->gapless_play_thread_cond);
4670 player->bus_msg_q = g_queue_new();
4671 if (!player->bus_msg_q) {
4672 LOGE("failed to create queue for bus_msg");
4673 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4677 ret = _mmplayer_initialize_video_capture(player);
4678 if (ret != MM_ERROR_NONE) {
4679 LOGE("failed to initialize video capture");
4683 /* initialize resource manager */
4684 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4685 __resource_release_cb, player, &player->resource_manager)
4686 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4687 LOGE("failed to initialize resource manager");
4688 ret = MM_ERROR_PLAYER_INTERNAL;
4692 /* create video bo lock and cond */
4693 g_mutex_init(&player->video_bo_mutex);
4694 g_cond_init(&player->video_bo_cond);
4696 /* create subtitle info lock and cond */
4697 g_mutex_init(&player->subtitle_info_mutex);
4698 g_cond_init(&player->subtitle_info_cond);
4700 player->streaming_type = STREAMING_SERVICE_NONE;
4702 /* give default value of audio effect setting */
4703 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4704 player->sound.rg_enable = false;
4705 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4707 player->play_subtitle = FALSE;
4708 player->has_closed_caption = FALSE;
4709 player->pending_resume = FALSE;
4710 if (player->ini.dump_element_keyword[0][0] == '\0')
4711 player->ini.set_dump_element_flag = FALSE;
4713 player->ini.set_dump_element_flag = TRUE;
4715 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4716 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4717 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4719 /* Set video360 settings to their defaults for just-created player.
4722 player->is_360_feature_enabled = FALSE;
4723 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4724 LOGI("spherical feature info: %d", enabled);
4726 player->is_360_feature_enabled = TRUE;
4728 LOGE("failed to get spherical feature info");
4731 player->is_content_spherical = FALSE;
4732 player->is_video360_enabled = TRUE;
4733 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4734 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4735 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4736 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4737 player->video360_zoom = 1.0f;
4738 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4739 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4741 __mmplayer_initialize_video_roi(player);
4743 /* set player state to null */
4744 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4745 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4749 return MM_ERROR_NONE;
4753 g_mutex_clear(&player->fsink_lock);
4754 /* free update tag lock */
4755 g_mutex_clear(&player->update_tag_lock);
4756 g_queue_free(player->bus_msg_q);
4757 player->bus_msg_q = NULL;
4758 /* free gapless play thread */
4759 if (player->gapless_play_thread) {
4760 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4761 player->gapless_play_thread_exit = TRUE;
4762 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4763 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4765 g_thread_join(player->gapless_play_thread);
4766 player->gapless_play_thread = NULL;
4768 g_mutex_clear(&player->gapless_play_thread_mutex);
4769 g_cond_clear(&player->gapless_play_thread_cond);
4772 /* release attributes */
4773 _mmplayer_deconstruct_attribute(handle);
4781 __mmplayer_init_gstreamer(mmplayer_t *player)
4783 static gboolean initialized = FALSE;
4784 static const int max_argc = 50;
4786 gchar **argv = NULL;
4787 gchar **argv2 = NULL;
4793 LOGD("gstreamer already initialized.");
4798 argc = malloc(sizeof(int));
4799 argv = malloc(sizeof(gchar *) * max_argc);
4800 argv2 = malloc(sizeof(gchar *) * max_argc);
4802 if (!argc || !argv || !argv2)
4805 memset(argv, 0, sizeof(gchar *) * max_argc);
4806 memset(argv2, 0, sizeof(gchar *) * max_argc);
4810 argv[0] = g_strdup("mmplayer");
4813 for (i = 0; i < 5; i++) {
4814 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4815 if (strlen(player->ini.gst_param[i]) > 0) {
4816 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4821 /* we would not do fork for scanning plugins */
4822 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4825 /* check disable registry scan */
4826 if (player->ini.skip_rescan) {
4827 argv[*argc] = g_strdup("--gst-disable-registry-update");
4831 /* check disable segtrap */
4832 if (player->ini.disable_segtrap) {
4833 argv[*argc] = g_strdup("--gst-disable-segtrap");
4837 LOGD("initializing gstreamer with following parameter");
4838 LOGD("argc : %d", *argc);
4841 for (i = 0; i < arg_count; i++) {
4843 LOGD("argv[%d] : %s", i, argv2[i]);
4846 /* initializing gstreamer */
4847 if (!gst_init_check(argc, &argv, &err)) {
4848 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4855 for (i = 0; i < arg_count; i++) {
4857 LOGD("release - argv[%d] : %s", i, argv2[i]);
4859 MMPLAYER_FREEIF(argv2[i]);
4862 MMPLAYER_FREEIF(argv);
4863 MMPLAYER_FREEIF(argv2);
4864 MMPLAYER_FREEIF(argc);
4874 for (i = 0; i < arg_count; i++) {
4875 LOGD("free[%d] : %s", i, argv2[i]);
4876 MMPLAYER_FREEIF(argv2[i]);
4879 MMPLAYER_FREEIF(argv);
4880 MMPLAYER_FREEIF(argv2);
4881 MMPLAYER_FREEIF(argc);
4887 __mmplayer_check_async_state_transition(mmplayer_t *player)
4889 GstState element_state = GST_STATE_VOID_PENDING;
4890 GstState element_pending_state = GST_STATE_VOID_PENDING;
4891 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4892 GstElement *element = NULL;
4893 gboolean async = FALSE;
4895 /* check player handle */
4896 MMPLAYER_RETURN_IF_FAIL(player &&
4898 player->pipeline->mainbin &&
4899 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4902 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4904 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4905 LOGD("don't need to check the pipeline state");
4909 MMPLAYER_PRINT_STATE(player);
4911 /* wait for state transition */
4912 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4913 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4915 if (ret == GST_STATE_CHANGE_FAILURE) {
4916 LOGE(" [%s] state : %s pending : %s",
4917 GST_ELEMENT_NAME(element),
4918 gst_element_state_get_name(element_state),
4919 gst_element_state_get_name(element_pending_state));
4921 /* dump state of all element */
4922 _mmplayer_dump_pipeline_state(player);
4927 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4932 _mmplayer_destroy(MMHandleType handle)
4934 mmplayer_t *player = MM_PLAYER_CAST(handle);
4938 /* check player handle */
4939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4941 /* destroy can called at anytime */
4942 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4944 /* check async state transition */
4945 __mmplayer_check_async_state_transition(player);
4947 /* release gapless play thread */
4948 if (player->gapless_play_thread) {
4949 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4950 player->gapless_play_thread_exit = TRUE;
4951 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4952 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4954 LOGD("waitting for gapless play thread exit");
4955 g_thread_join(player->gapless_play_thread);
4956 g_mutex_clear(&player->gapless_play_thread_mutex);
4957 g_cond_clear(&player->gapless_play_thread_cond);
4958 LOGD("gapless play thread released");
4961 _mmplayer_release_video_capture(player);
4963 /* de-initialize resource manager */
4964 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4965 player->resource_manager))
4966 LOGE("failed to deinitialize resource manager");
4968 /* release pipeline */
4969 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4970 LOGE("failed to destory pipeline");
4971 return MM_ERROR_PLAYER_INTERNAL;
4974 g_queue_free(player->bus_msg_q);
4976 /* release subtitle info lock and cond */
4977 g_mutex_clear(&player->subtitle_info_mutex);
4978 g_cond_clear(&player->subtitle_info_cond);
4980 __mmplayer_release_dump_list(player->dump_list);
4982 /* release miscellaneous information */
4983 __mmplayer_release_misc(player);
4985 /* release miscellaneous information.
4986 these info needs to be released after pipeline is destroyed. */
4987 __mmplayer_release_misc_post(player);
4989 /* release attributes */
4990 _mmplayer_deconstruct_attribute(handle);
4993 g_mutex_clear(&player->fsink_lock);
4996 g_mutex_clear(&player->update_tag_lock);
4998 /* release video bo lock and cond */
4999 g_mutex_clear(&player->video_bo_mutex);
5000 g_cond_clear(&player->video_bo_cond);
5004 return MM_ERROR_NONE;
5008 _mmplayer_realize(MMHandleType hplayer)
5010 mmplayer_t *player = (mmplayer_t *)hplayer;
5013 MMHandleType attrs = 0;
5014 int ret = MM_ERROR_NONE;
5018 /* check player handle */
5019 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5021 /* check current state */
5022 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5024 attrs = MMPLAYER_GET_ATTRS(player);
5026 LOGE("fail to get attributes.");
5027 return MM_ERROR_PLAYER_INTERNAL;
5029 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5030 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5032 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5033 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5035 if (ret != MM_ERROR_NONE) {
5036 LOGE("failed to parse profile");
5041 if (uri && (strstr(uri, "es_buff://"))) {
5042 if (strstr(uri, "es_buff://push_mode"))
5043 player->es_player_push_mode = TRUE;
5045 player->es_player_push_mode = FALSE;
5048 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5049 LOGW("mms protocol is not supported format.");
5050 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5053 if (MMPLAYER_IS_STREAMING(player))
5054 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5056 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5058 player->smooth_streaming = FALSE;
5059 player->videodec_linked = 0;
5060 player->audiodec_linked = 0;
5061 player->textsink_linked = 0;
5062 player->is_external_subtitle_present = FALSE;
5063 player->is_external_subtitle_added_now = FALSE;
5064 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5065 player->video360_metadata.is_spherical = -1;
5066 player->is_openal_plugin_used = FALSE;
5067 player->demux_pad_index = 0;
5068 player->subtitle_language_list = NULL;
5069 player->is_subtitle_force_drop = FALSE;
5071 _mmplayer_track_initialize(player);
5072 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5074 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5075 gint prebuffer_ms = 0, rebuffer_ms = 0;
5077 player->streamer = _mm_player_streaming_create();
5078 _mm_player_streaming_initialize(player->streamer, TRUE);
5080 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5081 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5083 if (prebuffer_ms > 0) {
5084 prebuffer_ms = MAX(prebuffer_ms, 1000);
5085 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5088 if (rebuffer_ms > 0) {
5089 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5090 rebuffer_ms = MAX(rebuffer_ms, 1000);
5091 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5094 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5095 player->streamer->buffering_req.rebuffer_time);
5098 /* realize pipeline */
5099 ret = __mmplayer_gst_realize(player);
5100 if (ret != MM_ERROR_NONE)
5101 LOGE("fail to realize the player.");
5103 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5111 _mmplayer_unrealize(MMHandleType hplayer)
5113 mmplayer_t *player = (mmplayer_t *)hplayer;
5114 int ret = MM_ERROR_NONE;
5118 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5120 MMPLAYER_CMD_UNLOCK(player);
5121 /* destroy the gst bus msg thread which is created during realize.
5122 this funct have to be called before getting cmd lock. */
5123 _mmplayer_bus_msg_thread_destroy(player);
5124 MMPLAYER_CMD_LOCK(player);
5126 /* check current state */
5127 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5129 /* check async state transition */
5130 __mmplayer_check_async_state_transition(player);
5132 /* unrealize pipeline */
5133 ret = __mmplayer_gst_unrealize(player);
5135 if (!player->interrupted_by_resource) {
5136 int rm_ret = MM_ERROR_NONE;
5137 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5139 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5140 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5141 if (rm_ret != MM_ERROR_NONE)
5142 LOGE("failed to release [%d] resources", res_idx);
5151 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5153 mmplayer_t *player = (mmplayer_t *)hplayer;
5155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5157 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5161 _mmplayer_get_state(MMHandleType hplayer, int *state)
5163 mmplayer_t *player = (mmplayer_t *)hplayer;
5165 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5167 *state = MMPLAYER_CURRENT_STATE(player);
5169 return MM_ERROR_NONE;
5173 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5175 GstElement *vol_element = NULL;
5176 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5180 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5182 /* check pipeline handle */
5183 if (!player->pipeline || !player->pipeline->audiobin) {
5184 LOGD("'%s' will be applied when audiobin is created", prop_name);
5186 /* NOTE : stored value will be used in create_audiobin
5187 * returning MM_ERROR_NONE here makes application to able to
5188 * set audio volume or mute at anytime.
5190 return MM_ERROR_NONE;
5193 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5194 volume_elem_id = MMPLAYER_A_SINK;
5196 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5198 LOGE("failed to get vol element %d", volume_elem_id);
5199 return MM_ERROR_PLAYER_INTERNAL;
5202 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5204 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5205 LOGE("there is no '%s' property", prop_name);
5206 return MM_ERROR_PLAYER_INTERNAL;
5209 if (!strcmp(prop_name, "volume")) {
5210 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5211 } else if (!strcmp(prop_name, "mute")) {
5212 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5214 LOGE("invalid property %s", prop_name);
5215 return MM_ERROR_PLAYER_INTERNAL;
5218 return MM_ERROR_NONE;
5222 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5224 int ret = MM_ERROR_NONE;
5225 mmplayer_t *player = (mmplayer_t *)hplayer;
5228 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5230 LOGD("volume = %f", volume);
5232 /* invalid factor range or not */
5233 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5234 LOGE("Invalid volume value");
5235 return MM_ERROR_INVALID_ARGUMENT;
5238 player->sound.volume = volume;
5240 ret = __mmplayer_gst_set_volume_property(player, "volume");
5247 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5249 mmplayer_t *player = (mmplayer_t *)hplayer;
5253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5254 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5256 *volume = player->sound.volume;
5258 LOGD("current vol = %f", *volume);
5261 return MM_ERROR_NONE;
5265 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5267 int ret = MM_ERROR_NONE;
5268 mmplayer_t *player = (mmplayer_t *)hplayer;
5271 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273 LOGD("mute = %d", mute);
5275 player->sound.mute = mute;
5277 ret = __mmplayer_gst_set_volume_property(player, "mute");
5284 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5286 mmplayer_t *player = (mmplayer_t *)hplayer;
5290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5291 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5293 *mute = player->sound.mute;
5295 LOGD("current mute = %d", *mute);
5299 return MM_ERROR_NONE;
5303 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5305 mmplayer_t *player = (mmplayer_t *)hplayer;
5309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5311 player->audio_stream_changed_cb = callback;
5312 player->audio_stream_changed_cb_user_param = user_param;
5313 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5317 return MM_ERROR_NONE;
5321 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5323 mmplayer_t *player = (mmplayer_t *)hplayer;
5327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5329 player->audio_decoded_cb = callback;
5330 player->audio_decoded_cb_user_param = user_param;
5331 player->audio_extract_opt = opt;
5332 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5336 return MM_ERROR_NONE;
5340 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5342 mmplayer_t *player = (mmplayer_t *)hplayer;
5346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5348 if (callback && !player->bufmgr)
5349 player->bufmgr = tbm_bufmgr_init(-1);
5351 player->set_mode.video_export = (callback) ? true : false;
5352 player->video_decoded_cb = callback;
5353 player->video_decoded_cb_user_param = user_param;
5355 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5359 return MM_ERROR_NONE;
5363 _mmplayer_start(MMHandleType hplayer)
5365 mmplayer_t *player = (mmplayer_t *)hplayer;
5366 gint ret = MM_ERROR_NONE;
5370 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5372 /* check current state */
5373 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5375 /* start pipeline */
5376 ret = _mmplayer_gst_start(player);
5377 if (ret != MM_ERROR_NONE)
5378 LOGE("failed to start player.");
5380 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5381 LOGD("force playing start even during buffering");
5382 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5390 /* NOTE: post "not supported codec message" to application
5391 * when one codec is not found during AUTOPLUGGING in MSL.
5392 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5393 * And, if any codec is not found, don't send message here.
5394 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5397 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5399 MMMessageParamType msg_param;
5400 memset(&msg_param, 0, sizeof(MMMessageParamType));
5401 gboolean post_msg_direct = FALSE;
5405 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5407 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5408 player->not_supported_codec, player->can_support_codec);
5410 if (player->not_found_demuxer) {
5411 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5412 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5414 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5415 MMPLAYER_FREEIF(msg_param.data);
5417 return MM_ERROR_NONE;
5420 if (player->not_supported_codec) {
5421 if (player->can_support_codec) {
5422 // There is one codec to play
5423 post_msg_direct = TRUE;
5425 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5426 post_msg_direct = TRUE;
5429 if (post_msg_direct) {
5430 MMMessageParamType msg_param;
5431 memset(&msg_param, 0, sizeof(MMMessageParamType));
5433 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5434 LOGW("not found AUDIO codec, posting error code to application.");
5436 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5437 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5438 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5439 LOGW("not found VIDEO codec, posting error code to application.");
5441 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5442 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5447 MMPLAYER_FREEIF(msg_param.data);
5449 return MM_ERROR_NONE;
5451 // no any supported codec case
5452 LOGW("not found any codec, posting error code to application.");
5454 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5455 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5456 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5458 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5459 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5462 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5464 MMPLAYER_FREEIF(msg_param.data);
5470 return MM_ERROR_NONE;
5474 __mmplayer_check_pipeline(mmplayer_t *player)
5476 GstState element_state = GST_STATE_VOID_PENDING;
5477 GstState element_pending_state = GST_STATE_VOID_PENDING;
5479 int ret = MM_ERROR_NONE;
5481 if (!player->gapless.reconfigure)
5484 LOGW("pipeline is under construction.");
5486 MMPLAYER_PLAYBACK_LOCK(player);
5487 MMPLAYER_PLAYBACK_UNLOCK(player);
5489 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5491 /* wait for state transition */
5492 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5493 if (ret == GST_STATE_CHANGE_FAILURE)
5494 LOGE("failed to change pipeline state within %d sec", timeout);
5497 /* NOTE : it should be able to call 'stop' anytime*/
5499 _mmplayer_stop(MMHandleType hplayer)
5501 mmplayer_t *player = (mmplayer_t *)hplayer;
5502 int ret = MM_ERROR_NONE;
5506 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5508 /* check current state */
5509 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5511 /* check pipline building state */
5512 __mmplayer_check_pipeline(player);
5513 __mmplayer_reset_gapless_state(player);
5515 /* NOTE : application should not wait for EOS after calling STOP */
5516 _mmplayer_cancel_eos_timer(player);
5519 player->seek_state = MMPLAYER_SEEK_NONE;
5522 ret = _mmplayer_gst_stop(player);
5524 if (ret != MM_ERROR_NONE)
5525 LOGE("failed to stop player.");
5533 _mmplayer_pause(MMHandleType hplayer)
5535 mmplayer_t *player = (mmplayer_t *)hplayer;
5536 gint64 pos_nsec = 0;
5537 gboolean async = FALSE;
5538 gint ret = MM_ERROR_NONE;
5542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5544 /* check current state */
5545 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5547 /* check pipline building state */
5548 __mmplayer_check_pipeline(player);
5550 switch (MMPLAYER_CURRENT_STATE(player)) {
5551 case MM_PLAYER_STATE_READY:
5553 /* check prepare async or not.
5554 * In the case of streaming playback, it's recommned to avoid blocking wait.
5556 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5557 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5559 /* Changing back sync of rtspsrc to async */
5560 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5561 LOGD("async prepare working mode for rtsp");
5567 case MM_PLAYER_STATE_PLAYING:
5569 /* NOTE : store current point to overcome some bad operation
5570 *(returning zero when getting current position in paused state) of some
5573 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5574 LOGW("getting current position failed in paused");
5576 player->last_position = pos_nsec;
5578 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5579 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5580 This causes problem is position calculation during normal pause resume scenarios also.
5581 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5582 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5583 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5584 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5590 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5591 LOGD("doing async pause in case of ms buff src");
5595 /* pause pipeline */
5596 ret = _mmplayer_gst_pause(player, async);
5598 if (ret != MM_ERROR_NONE)
5599 LOGE("failed to pause player. ret : 0x%x", ret);
5601 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5602 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5603 LOGE("failed to update display_rotation");
5611 /* in case of streaming, pause could take long time.*/
5613 _mmplayer_abort_pause(MMHandleType hplayer)
5615 mmplayer_t *player = (mmplayer_t *)hplayer;
5616 int ret = MM_ERROR_NONE;
5620 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5622 player->pipeline->mainbin,
5623 MM_ERROR_PLAYER_NOT_INITIALIZED);
5625 LOGD("set the pipeline state to READY");
5627 /* set state to READY */
5628 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5629 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5630 if (ret != MM_ERROR_NONE) {
5631 LOGE("fail to change state to READY");
5632 return MM_ERROR_PLAYER_INTERNAL;
5635 LOGD("succeeded in changing state to READY");
5640 _mmplayer_resume(MMHandleType hplayer)
5642 mmplayer_t *player = (mmplayer_t *)hplayer;
5643 int ret = MM_ERROR_NONE;
5644 gboolean async = FALSE;
5648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5650 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5651 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5652 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5656 /* Changing back sync mode rtspsrc to async */
5657 LOGD("async resume for rtsp case");
5661 /* check current state */
5662 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5664 ret = _mmplayer_gst_resume(player, async);
5665 if (ret != MM_ERROR_NONE)
5666 LOGE("failed to resume player.");
5668 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5669 LOGD("force resume even during buffering");
5670 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5679 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5681 mmplayer_t *player = (mmplayer_t *)hplayer;
5682 gint64 pos_nsec = 0;
5683 int ret = MM_ERROR_NONE;
5685 signed long long start = 0, stop = 0;
5686 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5689 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5690 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5692 /* The sound of video is not supported under 0.0 and over 2.0. */
5693 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5694 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5697 _mmplayer_set_mute(hplayer, mute);
5699 if (player->playback_rate == rate)
5700 return MM_ERROR_NONE;
5702 /* If the position is reached at start potion during fast backward, EOS is posted.
5703 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5705 player->playback_rate = rate;
5707 current_state = MMPLAYER_CURRENT_STATE(player);
5709 if (current_state != MM_PLAYER_STATE_PAUSED)
5710 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5712 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5714 if ((current_state == MM_PLAYER_STATE_PAUSED)
5715 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5716 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5717 pos_nsec = player->last_position;
5722 stop = GST_CLOCK_TIME_NONE;
5724 start = GST_CLOCK_TIME_NONE;
5728 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5729 player->playback_rate,
5731 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5732 GST_SEEK_TYPE_SET, start,
5733 GST_SEEK_TYPE_SET, stop)) {
5734 LOGE("failed to set speed playback");
5735 return MM_ERROR_PLAYER_SEEK;
5738 LOGD("succeeded to set speed playback as %0.1f", rate);
5742 return MM_ERROR_NONE;;
5746 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5748 mmplayer_t *player = (mmplayer_t *)hplayer;
5749 int ret = MM_ERROR_NONE;
5753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5755 /* check pipline building state */
5756 __mmplayer_check_pipeline(player);
5758 ret = _mmplayer_gst_set_position(player, position, FALSE);
5766 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5768 mmplayer_t *player = (mmplayer_t *)hplayer;
5769 int ret = MM_ERROR_NONE;
5771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5772 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5774 if (g_strrstr(player->type, "video/mpegts"))
5775 __mmplayer_update_duration_value(player);
5777 *duration = player->duration;
5782 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5784 mmplayer_t *player = (mmplayer_t *)hplayer;
5785 int ret = MM_ERROR_NONE;
5787 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5789 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5795 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5797 mmplayer_t *player = (mmplayer_t *)hplayer;
5798 int ret = MM_ERROR_NONE;
5802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5804 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5812 __mmplayer_is_midi_type(gchar *str_caps)
5814 if ((g_strrstr(str_caps, "audio/midi")) ||
5815 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5816 (g_strrstr(str_caps, "application/x-smaf")) ||
5817 (g_strrstr(str_caps, "audio/x-imelody")) ||
5818 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5819 (g_strrstr(str_caps, "audio/xmf")) ||
5820 (g_strrstr(str_caps, "audio/mxmf"))) {
5829 __mmplayer_is_only_mp3_type(gchar *str_caps)
5831 if (g_strrstr(str_caps, "application/x-id3") ||
5832 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5838 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5840 GstStructure *caps_structure = NULL;
5841 gint samplerate = 0;
5845 MMPLAYER_RETURN_IF_FAIL(player && caps);
5847 caps_structure = gst_caps_get_structure(caps, 0);
5849 /* set stream information */
5850 gst_structure_get_int(caps_structure, "rate", &samplerate);
5851 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5853 gst_structure_get_int(caps_structure, "channels", &channels);
5854 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5856 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5860 __mmplayer_update_content_type_info(mmplayer_t *player)
5863 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5865 if (__mmplayer_is_midi_type(player->type)) {
5866 player->bypass_audio_effect = TRUE;
5870 if (!player->streamer) {
5871 LOGD("no need to check streaming type");
5875 if (g_strrstr(player->type, "application/x-hls")) {
5876 /* If it can't know exact type when it parses uri because of redirection case,
5877 * it will be fixed by typefinder or when doing autoplugging.
5879 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5880 player->streamer->is_adaptive_streaming = TRUE;
5881 } else if (g_strrstr(player->type, "application/dash+xml")) {
5882 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5883 player->streamer->is_adaptive_streaming = TRUE;
5886 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5887 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5888 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5890 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5891 if (player->streamer->is_adaptive_streaming)
5892 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5894 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5898 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5903 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5904 GstCaps *caps, gpointer data)
5906 mmplayer_t *player = (mmplayer_t *)data;
5911 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5913 /* store type string */
5914 MMPLAYER_FREEIF(player->type);
5915 player->type = gst_caps_to_string(caps);
5917 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5918 player, player->type, probability, gst_caps_get_size(caps));
5920 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5921 (g_strrstr(player->type, "audio/x-raw-int"))) {
5922 LOGE("not support media format");
5924 if (player->msg_posted == FALSE) {
5925 MMMessageParamType msg_param;
5926 memset(&msg_param, 0, sizeof(MMMessageParamType));
5928 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5929 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5931 /* don't post more if one was sent already */
5932 player->msg_posted = TRUE;
5937 __mmplayer_update_content_type_info(player);
5939 pad = gst_element_get_static_pad(tf, "src");
5941 LOGE("fail to get typefind src pad.");
5945 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5946 gboolean async = FALSE;
5947 LOGE("failed to autoplug %s", player->type);
5949 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5951 if (async && player->msg_posted == FALSE)
5952 __mmplayer_handle_missed_plugin(player);
5956 gst_object_unref(GST_OBJECT(pad));
5964 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5966 GstElement *decodebin = NULL;
5970 /* create decodebin */
5971 decodebin = gst_element_factory_make("decodebin", NULL);
5974 LOGE("fail to create decodebin");
5978 /* raw pad handling signal */
5979 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5980 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5982 /* no-more-pad pad handling signal */
5983 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5984 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5986 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5987 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5989 /* This signal is emitted when a pad for which there is no further possible
5990 decoding is added to the decodebin.*/
5991 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5992 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5994 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5995 before looking for any elements that can handle that stream.*/
5996 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5997 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5999 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6000 before looking for any elements that can handle that stream.*/
6001 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6002 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6004 /* This signal is emitted once decodebin has finished decoding all the data.*/
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6006 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6008 /* This signal is emitted when a element is added to the bin.*/
6009 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6010 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6017 __mmplayer_gst_make_queue2(mmplayer_t *player)
6019 GstElement *queue2 = NULL;
6020 gint64 dur_bytes = 0L;
6021 mmplayer_gst_element_t *mainbin = NULL;
6022 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6025 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6027 mainbin = player->pipeline->mainbin;
6029 queue2 = gst_element_factory_make("queue2", "queue2");
6031 LOGE("failed to create buffering queue element");
6035 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6036 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6038 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6040 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6041 * skip the pull mode(file or ring buffering) setting. */
6042 if (dur_bytes > 0) {
6043 if (!g_strrstr(player->type, "video/mpegts")) {
6044 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6045 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6051 _mm_player_streaming_set_queue2(player->streamer,
6055 (guint64)dur_bytes); /* no meaning at the moment */
6061 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6063 mmplayer_gst_element_t *mainbin = NULL;
6064 GstElement *decodebin = NULL;
6065 GstElement *queue2 = NULL;
6066 GstPad *sinkpad = NULL;
6067 GstPad *qsrcpad = NULL;
6070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6072 mainbin = player->pipeline->mainbin;
6074 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6076 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6077 LOGW("need to check: muxed buffer is not null");
6080 queue2 = __mmplayer_gst_make_queue2(player);
6082 LOGE("failed to make queue2");
6086 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6087 LOGE("failed to add buffering queue");
6091 sinkpad = gst_element_get_static_pad(queue2, "sink");
6092 qsrcpad = gst_element_get_static_pad(queue2, "src");
6094 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6095 LOGE("failed to link [%s:%s]-[%s:%s]",
6096 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6100 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6101 LOGE("failed to sync queue2 state with parent");
6105 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6106 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6110 gst_object_unref(GST_OBJECT(sinkpad));
6114 /* create decodebin */
6115 decodebin = _mmplayer_gst_make_decodebin(player);
6117 LOGE("failed to make decodebin");
6121 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6122 LOGE("failed to add decodebin");
6126 /* to force caps on the decodebin element and avoid reparsing stuff by
6127 * typefind. It also avoids a deadlock in the way typefind activates pads in
6128 * the state change */
6129 g_object_set(decodebin, "sink-caps", caps, NULL);
6131 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6133 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6134 LOGE("failed to link [%s:%s]-[%s:%s]",
6135 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6139 gst_object_unref(GST_OBJECT(sinkpad));
6141 gst_object_unref(GST_OBJECT(qsrcpad));
6144 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6145 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6147 /* set decodebin property about buffer in streaming playback. *
6148 * in case of HLS/DASH, it does not need to have big buffer *
6149 * because it is kind of adaptive streaming. */
6150 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6151 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6152 gint high_percent = 0;
6154 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6155 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6157 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6159 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6161 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6162 "high-percent", high_percent,
6163 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6164 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6165 "max-size-buffers", 0, NULL); // disable or automatic
6168 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6169 LOGE("failed to sync decodebin state with parent");
6180 gst_object_unref(GST_OBJECT(sinkpad));
6183 gst_object_unref(GST_OBJECT(qsrcpad));
6186 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6187 * You need to explicitly set elements to the NULL state before
6188 * dropping the final reference, to allow them to clean up.
6190 gst_element_set_state(queue2, GST_STATE_NULL);
6192 /* And, it still has a parent "player".
6193 * You need to let the parent manage the object instead of unreffing the object directly.
6195 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6196 gst_object_unref(queue2);
6201 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6202 * You need to explicitly set elements to the NULL state before
6203 * dropping the final reference, to allow them to clean up.
6205 gst_element_set_state(decodebin, GST_STATE_NULL);
6207 /* And, it still has a parent "player".
6208 * You need to let the parent manage the object instead of unreffing the object directly.
6211 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6212 gst_object_unref(decodebin);
6220 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6225 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6227 LOGD("class : %s, mime : %s", factory_class, mime);
6229 /* add missing plugin */
6230 /* NOTE : msl should check missing plugin for image mime type.
6231 * Some motion jpeg clips can have playable audio track.
6232 * So, msl have to play audio after displaying popup written video format not supported.
6234 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6235 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6236 LOGD("not found demuxer");
6237 player->not_found_demuxer = TRUE;
6238 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6244 if (!g_strrstr(factory_class, "Demuxer")) {
6245 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6246 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6247 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6249 /* check that clip have multi tracks or not */
6250 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6251 LOGD("video plugin is already linked");
6253 LOGW("add VIDEO to missing plugin");
6254 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6255 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6257 } else if (g_str_has_prefix(mime, "audio")) {
6258 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6259 LOGD("audio plugin is already linked");
6261 LOGW("add AUDIO to missing plugin");
6262 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6263 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6271 return MM_ERROR_NONE;
6275 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6277 mmplayer_t *player = (mmplayer_t *)data;
6281 MMPLAYER_RETURN_IF_FAIL(player);
6283 /* remove fakesink. */
6284 if (!_mmplayer_gst_remove_fakesink(player,
6285 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6286 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6287 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6288 * source element are not same. To overcome this situation, this function will called
6289 * several places and several times. Therefore, this is not an error case.
6294 LOGD("[handle: %p] pipeline has completely constructed", player);
6296 if ((player->ini.async_start) &&
6297 (player->msg_posted == FALSE) &&
6298 (player->cmd >= MMPLAYER_COMMAND_START))
6299 __mmplayer_handle_missed_plugin(player);
6301 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6305 __mmplayer_check_profile(void)
6308 static int profile_tv = -1;
6310 if (__builtin_expect(profile_tv != -1, 1))
6313 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6314 switch (*profileName) {
6329 __mmplayer_get_next_uri(mmplayer_t *player)
6331 mmplayer_parse_profile_t profile;
6333 guint num_of_list = 0;
6336 num_of_list = g_list_length(player->uri_info.uri_list);
6337 uri_idx = player->uri_info.uri_idx;
6339 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6340 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6341 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6343 LOGW("next uri does not exist");
6347 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6348 LOGE("failed to parse profile");
6352 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6353 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6354 LOGW("uri type is not supported(%d)", profile.uri_type);
6358 LOGD("success to find next uri %d", uri_idx);
6362 if (uri_idx == num_of_list) {
6363 LOGE("failed to find next uri");
6367 player->uri_info.uri_idx = uri_idx;
6368 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6370 if (mm_attrs_commit_all(player->attrs)) {
6371 LOGE("failed to commit");
6375 SECURE_LOGD("next playback uri: %s", uri);
6380 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6382 #define REPEAT_COUNT_INFINITE -1
6383 #define REPEAT_COUNT_MIN 2
6384 #define ORIGINAL_URI_ONLY 1
6386 MMHandleType attrs = 0;
6390 guint num_of_uri = 0;
6391 int profile_tv = -1;
6395 LOGD("checking for gapless play option");
6397 if (player->build_audio_offload) {
6398 LOGE("offload path is not supportable.");
6402 if (player->pipeline->textbin) {
6403 LOGE("subtitle path is enabled. gapless play is not supported.");
6407 attrs = MMPLAYER_GET_ATTRS(player);
6409 LOGE("fail to get attributes.");
6413 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6415 /* gapless playback is not supported in case of video at TV profile. */
6416 profile_tv = __mmplayer_check_profile();
6417 if (profile_tv && video) {
6418 LOGW("not support video gapless playback");
6422 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6423 LOGE("failed to get play count");
6425 if (mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless) != MM_ERROR_NONE)
6426 LOGE("failed to get gapless mode");
6428 /* check repeat count in case of audio */
6430 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6431 LOGW("gapless is disabled");
6435 num_of_uri = g_list_length(player->uri_info.uri_list);
6437 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6439 if (num_of_uri == ORIGINAL_URI_ONLY) {
6440 /* audio looping path */
6441 if (count >= REPEAT_COUNT_MIN) {
6442 /* decrease play count */
6443 /* we succeeded to rewind. update play count and then wait for next EOS */
6445 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6446 /* commit attribute */
6447 if (mm_attrs_commit_all(attrs))
6448 LOGE("failed to commit attribute");
6450 } else if (count != REPEAT_COUNT_INFINITE) {
6451 LOGD("there is no next uri and no repeat");
6454 LOGD("looping cnt %d", count);
6456 /* gapless playback path */
6457 if (!__mmplayer_get_next_uri(player)) {
6458 LOGE("failed to get next uri");
6465 LOGE("unable to play gapless path. EOS will be posted soon");
6470 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6472 mmplayer_selector_t *selector = &player->selector[type];
6473 mmplayer_gst_element_t *sinkbin = NULL;
6474 main_element_id_e selectorId = MMPLAYER_M_NUM;
6475 main_element_id_e sinkId = MMPLAYER_M_NUM;
6476 GstPad *srcpad = NULL;
6477 GstPad *sinkpad = NULL;
6478 gboolean send_notice = FALSE;
6481 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6483 LOGD("type %d", type);
6486 case MM_PLAYER_TRACK_TYPE_AUDIO:
6487 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6488 sinkId = MMPLAYER_A_BIN;
6489 sinkbin = player->pipeline->audiobin;
6491 case MM_PLAYER_TRACK_TYPE_VIDEO:
6492 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6493 sinkId = MMPLAYER_V_BIN;
6494 sinkbin = player->pipeline->videobin;
6497 case MM_PLAYER_TRACK_TYPE_TEXT:
6498 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6499 sinkId = MMPLAYER_T_BIN;
6500 sinkbin = player->pipeline->textbin;
6503 LOGE("requested type is not supportable");
6508 if (player->pipeline->mainbin[selectorId].gst) {
6511 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6513 if (selector->event_probe_id != 0)
6514 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6515 selector->event_probe_id = 0;
6517 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6518 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6520 if (srcpad && sinkpad) {
6521 /* after getting drained signal there is no data flows, so no need to do pad_block */
6522 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6523 gst_pad_unlink(srcpad, sinkpad);
6525 /* send custom event to sink pad to handle it at video sink */
6527 LOGD("send custom event to sinkpad");
6528 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6529 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6530 gst_pad_send_event(sinkpad, event);
6534 gst_object_unref(sinkpad);
6537 gst_object_unref(srcpad);
6540 LOGD("selector release");
6542 /* release and unref requests pad from the selector */
6543 for (n = 0; n < selector->channels->len; n++) {
6544 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6545 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6547 g_ptr_array_set_size(selector->channels, 0);
6549 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6550 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6552 player->pipeline->mainbin[selectorId].gst = NULL;
6560 __mmplayer_deactivate_old_path(mmplayer_t *player)
6563 MMPLAYER_RETURN_IF_FAIL(player);
6565 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6566 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6567 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6568 LOGE("deactivate selector error");
6572 _mmplayer_track_destroy(player);
6573 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6575 if (player->streamer) {
6576 _mm_player_streaming_initialize(player->streamer, FALSE);
6577 _mm_player_streaming_destroy(player->streamer);
6578 player->streamer = NULL;
6581 MMPLAYER_PLAYBACK_LOCK(player);
6582 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6589 if (!player->msg_posted) {
6590 MMMessageParamType msg = {0,};
6593 msg.code = MM_ERROR_PLAYER_INTERNAL;
6594 LOGE("gapless_uri_play> deactivate error");
6596 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6597 player->msg_posted = TRUE;
6603 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6605 int result = MM_ERROR_NONE;
6606 mmplayer_t *player = (mmplayer_t *)hplayer;
6609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6611 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6612 if (mm_attrs_commit_all(player->attrs)) {
6613 LOGE("failed to commit the original uri.");
6614 result = MM_ERROR_PLAYER_INTERNAL;
6616 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6617 LOGE("failed to add the original uri in the uri list.");
6625 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6627 mmplayer_t *player = (mmplayer_t *)hplayer;
6628 guint num_of_list = 0;
6632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6633 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6635 if (player->pipeline && player->pipeline->textbin) {
6636 LOGE("subtitle path is enabled.");
6637 return MM_ERROR_PLAYER_INVALID_STATE;
6640 num_of_list = g_list_length(player->uri_info.uri_list);
6642 if (is_first_path) {
6643 if (num_of_list == 0) {
6644 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6645 SECURE_LOGD("add original path : %s", uri);
6647 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6648 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6650 SECURE_LOGD("change original path : %s", uri);
6653 MMHandleType attrs = 0;
6654 attrs = MMPLAYER_GET_ATTRS(player);
6656 if (num_of_list == 0) {
6657 char *original_uri = NULL;
6660 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6662 if (!original_uri) {
6663 LOGE("there is no original uri.");
6664 return MM_ERROR_PLAYER_INVALID_STATE;
6667 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6668 player->uri_info.uri_idx = 0;
6670 SECURE_LOGD("add original path at first : %s", original_uri);
6674 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6675 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6679 return MM_ERROR_NONE;
6683 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6685 mmplayer_t *player = (mmplayer_t *)hplayer;
6686 char *next_uri = NULL;
6687 guint num_of_list = 0;
6690 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6692 num_of_list = g_list_length(player->uri_info.uri_list);
6694 if (num_of_list > 0) {
6695 gint uri_idx = player->uri_info.uri_idx;
6697 if (uri_idx < num_of_list-1)
6702 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6703 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6705 *uri = g_strdup(next_uri);
6709 return MM_ERROR_NONE;
6713 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6714 GstCaps *caps, gpointer data)
6716 mmplayer_t *player = (mmplayer_t *)data;
6717 const gchar *klass = NULL;
6718 const gchar *mime = NULL;
6719 gchar *caps_str = NULL;
6721 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6722 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6723 caps_str = gst_caps_to_string(caps);
6725 LOGW("unknown type of caps : %s from %s",
6726 caps_str, GST_ELEMENT_NAME(elem));
6728 MMPLAYER_FREEIF(caps_str);
6730 /* There is no available codec. */
6731 __mmplayer_check_not_supported_codec(player, klass, mime);
6735 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6736 GstCaps *caps, gpointer data)
6738 mmplayer_t *player = (mmplayer_t *)data;
6739 const char *mime = NULL;
6740 gboolean ret = TRUE;
6742 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6743 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6745 if (g_str_has_prefix(mime, "audio")) {
6746 GstStructure *caps_structure = NULL;
6747 gint samplerate = 0;
6749 gchar *caps_str = NULL;
6751 caps_structure = gst_caps_get_structure(caps, 0);
6752 gst_structure_get_int(caps_structure, "rate", &samplerate);
6753 gst_structure_get_int(caps_structure, "channels", &channels);
6755 if ((channels > 0 && samplerate == 0)) {
6756 LOGD("exclude audio...");
6760 caps_str = gst_caps_to_string(caps);
6761 /* set it directly because not sent by TAG */
6762 if (g_strrstr(caps_str, "mobile-xmf"))
6763 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6764 MMPLAYER_FREEIF(caps_str);
6765 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6766 MMMessageParamType msg_param;
6767 memset(&msg_param, 0, sizeof(MMMessageParamType));
6768 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6769 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6770 LOGD("video file is not supported on this device");
6772 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6773 LOGD("already video linked");
6776 LOGD("found new stream");
6783 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6785 gboolean ret = TRUE;
6786 GDBusConnection *conn = NULL;
6788 GVariant *result = NULL;
6789 const gchar *dbus_device_type = NULL;
6790 const gchar *dbus_ret = NULL;
6793 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6795 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6801 result = g_dbus_connection_call_sync(conn,
6802 "org.pulseaudio.Server",
6803 "/org/pulseaudio/StreamManager",
6804 "org.pulseaudio.StreamManager",
6805 "GetCurrentMediaRoutingPath",
6806 g_variant_new("(s)", "out"),
6807 G_VARIANT_TYPE("(ss)"),
6808 G_DBUS_CALL_FLAGS_NONE,
6812 if (!result || err) {
6813 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6819 /* device type is listed in stream-map.json at mmfw-sysconf */
6820 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6822 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6823 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6828 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6829 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6830 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6831 LOGD("audio offload is supportable");
6837 LOGD("audio offload is not supportable");
6841 g_variant_unref(result);
6842 g_object_unref(conn);
6847 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6849 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6850 gint64 position = 0;
6852 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6853 player->pipeline && player->pipeline->mainbin);
6855 MMPLAYER_CMD_LOCK(player);
6856 current_state = MMPLAYER_CURRENT_STATE(player);
6858 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6859 LOGW("getting current position failed in paused");
6861 _mmplayer_unrealize((MMHandleType)player);
6862 _mmplayer_realize((MMHandleType)player);
6864 _mmplayer_set_position((MMHandleType)player, position);
6866 /* async not to be blocked in streaming case */
6867 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6868 if (mm_attrs_commit_all(player->attrs))
6869 LOGE("failed to commit");
6871 _mmplayer_pause((MMHandleType)player);
6873 if (current_state == MM_PLAYER_STATE_PLAYING)
6874 _mmplayer_start((MMHandleType)player);
6875 MMPLAYER_CMD_UNLOCK(player);
6877 LOGD("rebuilding audio pipeline is completed.");
6880 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6882 mmplayer_t *player = (mmplayer_t *)user_data;
6883 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6884 gboolean is_supportable = FALSE;
6886 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6887 LOGW("failed to get device type");
6889 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6891 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6892 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6893 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6894 LOGD("ignore this dev connected info");
6898 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6899 if (player->build_audio_offload == is_supportable) {
6900 LOGD("keep current pipeline without re-building");
6904 /* rebuild pipeline */
6905 LOGD("re-build pipeline - offload: %d", is_supportable);
6906 player->build_audio_offload = FALSE;
6907 __mmplayer_rebuild_audio_pipeline(player);
6913 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6915 unsigned int id = 0;
6917 if (player->audio_device_cb_id != 0) {
6918 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6922 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6923 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6924 LOGD("added device connected cb (%u)", id);
6925 player->audio_device_cb_id = id;
6927 LOGW("failed to add device connected cb");
6935 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6937 gboolean ret = FALSE;
6938 GstElementFactory *factory = NULL;
6941 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6943 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6944 if (!__mmplayer_is_only_mp3_type(player->type))
6947 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6948 LOGD("there is no audio offload sink");
6952 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6953 LOGW("there is no audio device type to support offload");
6957 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6959 LOGW("there is no installed audio offload sink element");
6962 gst_object_unref(factory);
6964 if (__mmplayer_acquire_hw_resource(player,
6965 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6966 LOGE("failed to acquire audio offload decoder resource");
6970 if (!__mmplayer_add_audio_device_connected_cb(player))
6973 if (!__mmplayer_is_audio_offload_device_type(player))
6976 LOGD("audio offload can be built");
6981 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6987 static GstAutoplugSelectResult
6988 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6990 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6992 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6993 int audio_offload = 0;
6995 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6996 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6998 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6999 LOGD("expose audio path to build offload output path");
7000 player->build_audio_offload = TRUE;
7001 /* update codec info */
7002 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7003 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7004 player->audiodec_linked = 1;
7006 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7010 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7012 LOGD("audio codec type: %d", codec_type);
7013 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7014 /* sw codec will be skipped */
7015 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7016 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7017 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7018 ret = GST_AUTOPLUG_SELECT_SKIP;
7022 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7023 /* hw codec will be skipped */
7024 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7025 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7026 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7027 ret = GST_AUTOPLUG_SELECT_SKIP;
7032 /* set stream information */
7033 if (!player->audiodec_linked)
7034 __mmplayer_set_audio_attrs(player, caps);
7036 /* update codec info */
7037 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7038 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7039 player->audiodec_linked = 1;
7041 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7043 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7045 LOGD("video codec type: %d", codec_type);
7046 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7047 /* sw codec is skipped */
7048 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7049 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7050 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7051 ret = GST_AUTOPLUG_SELECT_SKIP;
7055 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7056 /* hw codec is skipped */
7057 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7058 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7059 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7065 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7067 /* mark video decoder for acquire */
7068 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7069 LOGW("video decoder resource is already acquired, skip it.");
7070 ret = GST_AUTOPLUG_SELECT_SKIP;
7074 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7075 LOGE("failed to acquire video decoder resource");
7076 ret = GST_AUTOPLUG_SELECT_SKIP;
7079 player->interrupted_by_resource = FALSE;
7082 /* update codec info */
7083 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7084 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7085 player->videodec_linked = 1;
7093 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7094 GstCaps *caps, GstElementFactory *factory, gpointer data)
7096 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7097 mmplayer_t *player = (mmplayer_t *)data;
7099 gchar *factory_name = NULL;
7100 gchar *caps_str = NULL;
7101 const gchar *klass = NULL;
7104 factory_name = GST_OBJECT_NAME(factory);
7105 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7106 caps_str = gst_caps_to_string(caps);
7108 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7110 /* store type string */
7111 if (player->type == NULL) {
7112 player->type = gst_caps_to_string(caps);
7113 __mmplayer_update_content_type_info(player);
7116 /* filtering exclude keyword */
7117 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7118 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7119 LOGW("skipping [%s] by exculde keyword [%s]",
7120 factory_name, player->ini.exclude_element_keyword[idx]);
7122 result = GST_AUTOPLUG_SELECT_SKIP;
7127 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7128 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7129 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7130 factory_name, player->ini.unsupported_codec_keyword[idx]);
7131 result = GST_AUTOPLUG_SELECT_SKIP;
7136 /* exclude webm format */
7137 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7138 * because webm format is not supportable.
7139 * If webm is disabled in "autoplug-continue", there is no state change
7140 * failure or error because the decodebin will expose the pad directly.
7141 * It make MSL invoke _prepare_async_callback.
7142 * So, we need to disable webm format in "autoplug-select" */
7143 if (caps_str && strstr(caps_str, "webm")) {
7144 LOGW("webm is not supported");
7145 result = GST_AUTOPLUG_SELECT_SKIP;
7149 /* check factory class for filtering */
7150 /* NOTE : msl don't need to use image plugins.
7151 * So, those plugins should be skipped for error handling.
7153 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7154 LOGD("skipping [%s] by not required", factory_name);
7155 result = GST_AUTOPLUG_SELECT_SKIP;
7159 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7160 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7161 // TO CHECK : subtitle if needed, add subparse exception.
7162 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7163 result = GST_AUTOPLUG_SELECT_SKIP;
7167 if (g_strrstr(factory_name, "mpegpsdemux")) {
7168 LOGD("skipping PS container - not support");
7169 result = GST_AUTOPLUG_SELECT_SKIP;
7173 if (g_strrstr(factory_name, "mssdemux"))
7174 player->smooth_streaming = TRUE;
7176 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7177 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7180 GstStructure *str = NULL;
7181 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7183 /* don't make video because of not required */
7184 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7185 (!player->set_mode.video_export)) {
7186 LOGD("no need video decoding, expose pad");
7187 result = GST_AUTOPLUG_SELECT_EXPOSE;
7191 /* get w/h for omx state-tune */
7192 /* FIXME: deprecated? */
7193 str = gst_caps_get_structure(caps, 0);
7194 gst_structure_get_int(str, "width", &width);
7197 if (player->v_stream_caps) {
7198 gst_caps_unref(player->v_stream_caps);
7199 player->v_stream_caps = NULL;
7202 player->v_stream_caps = gst_caps_copy(caps);
7203 LOGD("take caps for video state tune");
7204 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7208 if (g_strrstr(klass, "Codec/Decoder")) {
7209 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7210 if (result != GST_AUTOPLUG_SELECT_TRY) {
7211 LOGW("skip add decoder");
7217 MMPLAYER_FREEIF(caps_str);
7223 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7226 //mmplayer_t *player = (mmplayer_t *)data;
7227 GstCaps *caps = NULL;
7229 LOGD("[Decodebin2] pad-removed signal");
7231 caps = gst_pad_query_caps(new_pad, NULL);
7233 LOGW("query caps is NULL");
7237 gchar *caps_str = NULL;
7238 caps_str = gst_caps_to_string(caps);
7240 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7242 MMPLAYER_FREEIF(caps_str);
7243 gst_caps_unref(caps);
7247 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7249 mmplayer_t *player = (mmplayer_t *)data;
7250 GstIterator *iter = NULL;
7251 GValue item = { 0, };
7253 gboolean done = FALSE;
7254 gboolean is_all_drained = TRUE;
7257 MMPLAYER_RETURN_IF_FAIL(player);
7259 LOGD("__mmplayer_gst_decode_drained");
7261 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7262 LOGW("Fail to get cmd lock");
7266 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7267 !__mmplayer_verify_gapless_play_path(player)) {
7268 LOGD("decoding is finished.");
7269 __mmplayer_reset_gapless_state(player);
7270 MMPLAYER_CMD_UNLOCK(player);
7274 player->gapless.reconfigure = TRUE;
7276 /* check decodebin src pads whether they received EOS or not */
7277 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7280 switch (gst_iterator_next(iter, &item)) {
7281 case GST_ITERATOR_OK:
7282 pad = g_value_get_object(&item);
7283 if (pad && !GST_PAD_IS_EOS(pad)) {
7284 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7285 is_all_drained = FALSE;
7288 g_value_reset(&item);
7290 case GST_ITERATOR_RESYNC:
7291 gst_iterator_resync(iter);
7293 case GST_ITERATOR_ERROR:
7294 case GST_ITERATOR_DONE:
7299 g_value_unset(&item);
7300 gst_iterator_free(iter);
7302 if (!is_all_drained) {
7303 LOGD("Wait util the all pads get EOS.");
7304 MMPLAYER_CMD_UNLOCK(player);
7309 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7310 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7312 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7313 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7314 __mmplayer_deactivate_old_path(player);
7315 MMPLAYER_CMD_UNLOCK(player);
7321 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7323 mmplayer_t *player = (mmplayer_t *)data;
7324 const gchar *klass = NULL;
7325 gchar *factory_name = NULL;
7327 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7328 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7330 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7332 if (__mmplayer_add_dump_buffer_probe(player, element))
7333 LOGD("add buffer probe");
7335 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7336 gchar *selected = NULL;
7337 selected = g_strdup(GST_ELEMENT_NAME(element));
7338 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7341 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7342 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7343 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7345 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7346 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7348 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7349 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7350 "max-video-width", player->adaptive_info.limit.width,
7351 "max-video-height", player->adaptive_info.limit.height, NULL);
7353 } else if (g_strrstr(klass, "Demuxer")) {
7355 LOGD("plugged element is demuxer. take it");
7357 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7358 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7361 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7362 int surface_type = 0;
7364 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7367 // to support trust-zone only
7368 if (g_strrstr(factory_name, "asfdemux")) {
7369 LOGD("set file-location %s", player->profile.uri);
7370 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7371 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7372 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7373 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7374 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7375 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7376 (__mmplayer_is_only_mp3_type(player->type))) {
7377 LOGD("[mpegaudioparse] set streaming pull mode.");
7378 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7380 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7381 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7384 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7385 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7386 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7388 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7389 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7391 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7392 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7393 (MMPLAYER_IS_DASH_STREAMING(player))) {
7394 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7395 _mm_player_streaming_set_multiqueue(player->streamer, element);
7396 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7405 __mmplayer_release_misc(mmplayer_t *player)
7408 bool cur_mode = player->set_mode.rich_audio;
7411 MMPLAYER_RETURN_IF_FAIL(player);
7413 player->video_decoded_cb = NULL;
7414 player->video_decoded_cb_user_param = NULL;
7415 player->video_stream_prerolled = false;
7417 player->audio_decoded_cb = NULL;
7418 player->audio_decoded_cb_user_param = NULL;
7419 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7421 player->audio_stream_changed_cb = NULL;
7422 player->audio_stream_changed_cb_user_param = NULL;
7424 player->sent_bos = FALSE;
7425 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7427 player->seek_state = MMPLAYER_SEEK_NONE;
7429 player->total_bitrate = 0;
7430 player->total_maximum_bitrate = 0;
7432 player->not_found_demuxer = 0;
7434 player->last_position = 0;
7435 player->duration = 0;
7436 player->http_content_size = 0;
7437 player->not_supported_codec = MISSING_PLUGIN_NONE;
7438 player->can_support_codec = FOUND_PLUGIN_NONE;
7439 player->pending_seek.is_pending = false;
7440 player->pending_seek.pos = 0;
7441 player->msg_posted = FALSE;
7442 player->has_many_types = FALSE;
7443 player->is_subtitle_force_drop = FALSE;
7444 player->play_subtitle = FALSE;
7445 player->adjust_subtitle_pos = 0;
7446 player->has_closed_caption = FALSE;
7447 player->set_mode.video_export = false;
7448 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7449 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7451 player->set_mode.rich_audio = cur_mode;
7453 if (player->audio_device_cb_id > 0 &&
7454 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7455 LOGW("failed to remove audio device_connected_callback");
7456 player->audio_device_cb_id = 0;
7458 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7459 player->bitrate[i] = 0;
7460 player->maximum_bitrate[i] = 0;
7463 /* free memory related to audio effect */
7464 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7466 if (player->adaptive_info.var_list) {
7467 g_list_free_full(player->adaptive_info.var_list, g_free);
7468 player->adaptive_info.var_list = NULL;
7471 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7472 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7473 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7475 /* Reset video360 settings to their defaults in case if the pipeline is to be
7478 player->video360_metadata.is_spherical = -1;
7479 player->is_openal_plugin_used = FALSE;
7481 player->is_content_spherical = FALSE;
7482 player->is_video360_enabled = TRUE;
7483 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7484 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7485 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7486 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7487 player->video360_zoom = 1.0f;
7488 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7489 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7491 player->sound.rg_enable = false;
7493 __mmplayer_initialize_video_roi(player);
7498 __mmplayer_release_misc_post(mmplayer_t *player)
7500 char *original_uri = NULL;
7503 /* player->pipeline is already released before. */
7505 MMPLAYER_RETURN_IF_FAIL(player);
7507 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7509 /* clean found audio decoders */
7510 if (player->audio_decoders) {
7511 GList *a_dec = player->audio_decoders;
7512 for (; a_dec; a_dec = g_list_next(a_dec)) {
7513 gchar *name = a_dec->data;
7514 MMPLAYER_FREEIF(name);
7516 g_list_free(player->audio_decoders);
7517 player->audio_decoders = NULL;
7520 /* clean the uri list except original uri */
7521 if (player->uri_info.uri_list) {
7522 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7524 if (player->attrs) {
7525 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7526 LOGD("restore original uri = %s", original_uri);
7528 if (mm_attrs_commit_all(player->attrs))
7529 LOGE("failed to commit the original uri.");
7532 GList *uri_list = player->uri_info.uri_list;
7533 for (; uri_list; uri_list = g_list_next(uri_list)) {
7534 gchar *uri = uri_list->data;
7535 MMPLAYER_FREEIF(uri);
7537 g_list_free(player->uri_info.uri_list);
7538 player->uri_info.uri_list = NULL;
7541 /* clear the audio stream buffer list */
7542 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7544 /* clear the video stream bo list */
7545 __mmplayer_video_stream_destroy_bo_list(player);
7546 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7548 if (player->profile.input_mem.buf) {
7549 free(player->profile.input_mem.buf);
7550 player->profile.input_mem.buf = NULL;
7552 player->profile.input_mem.len = 0;
7553 player->profile.input_mem.offset = 0;
7555 player->uri_info.uri_idx = 0;
7560 __mmplayer_check_subtitle(mmplayer_t *player)
7562 MMHandleType attrs = 0;
7563 char *subtitle_uri = NULL;
7567 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7569 /* get subtitle attribute */
7570 attrs = MMPLAYER_GET_ATTRS(player);
7574 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7575 if (!subtitle_uri || !strlen(subtitle_uri))
7578 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7579 player->is_external_subtitle_present = TRUE;
7587 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7589 MMPLAYER_RETURN_IF_FAIL(player);
7591 if (player->eos_timer) {
7592 LOGD("cancel eos timer");
7593 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7594 player->eos_timer = 0;
7601 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7605 MMPLAYER_RETURN_IF_FAIL(player);
7606 MMPLAYER_RETURN_IF_FAIL(sink);
7608 player->sink_elements = g_list_append(player->sink_elements, sink);
7614 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7618 MMPLAYER_RETURN_IF_FAIL(player);
7619 MMPLAYER_RETURN_IF_FAIL(sink);
7621 player->sink_elements = g_list_remove(player->sink_elements, sink);
7627 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7628 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7630 mmplayer_signal_item_t *item = NULL;
7633 MMPLAYER_RETURN_IF_FAIL(player);
7635 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7636 LOGE("invalid signal type [%d]", type);
7640 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7642 LOGE("cannot connect signal [%s]", signal);
7647 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7648 player->signals[type] = g_list_append(player->signals[type], item);
7654 /* NOTE : be careful with calling this api. please refer to below glib comment
7655 * glib comment : Note that there is a bug in GObject that makes this function much
7656 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7657 * will no longer be called, but, the signal handler is not currently disconnected.
7658 * If the instance is itself being freed at the same time than this doesn't matter,
7659 * since the signal will automatically be removed, but if instance persists,
7660 * then the signal handler will leak. You should not remove the signal yourself
7661 * because in a future versions of GObject, the handler will automatically be
7664 * It's possible to work around this problem in a way that will continue to work
7665 * with future versions of GObject by checking that the signal handler is still
7666 * connected before disconnected it:
7668 * if (g_signal_handler_is_connected(instance, id))
7669 * g_signal_handler_disconnect(instance, id);
7672 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7674 GList *sig_list = NULL;
7675 mmplayer_signal_item_t *item = NULL;
7679 MMPLAYER_RETURN_IF_FAIL(player);
7681 LOGD("release signals type : %d", type);
7683 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7684 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7685 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7686 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7687 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7688 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7692 sig_list = player->signals[type];
7694 for (; sig_list; sig_list = sig_list->next) {
7695 item = sig_list->data;
7697 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7698 if (g_signal_handler_is_connected(item->obj, item->sig))
7699 g_signal_handler_disconnect(item->obj, item->sig);
7702 MMPLAYER_FREEIF(item);
7705 g_list_free(player->signals[type]);
7706 player->signals[type] = NULL;
7714 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7716 mmplayer_t *player = 0;
7717 int prev_display_surface_type = 0;
7718 void *prev_display_overlay = NULL;
7722 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7723 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7725 player = MM_PLAYER_CAST(handle);
7727 /* check video sinkbin is created */
7728 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7729 LOGE("Videosink is already created");
7730 return MM_ERROR_NONE;
7733 LOGD("videosink element is not yet ready");
7735 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7736 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7738 return MM_ERROR_INVALID_ARGUMENT;
7741 /* load previous attributes */
7742 if (player->attrs) {
7743 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7744 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7745 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7746 if (prev_display_surface_type == surface_type) {
7747 LOGD("incoming display surface type is same as previous one, do nothing..");
7749 return MM_ERROR_NONE;
7752 LOGE("failed to load attributes");
7754 return MM_ERROR_PLAYER_INTERNAL;
7757 /* videobin is not created yet, so we just set attributes related to display surface */
7758 LOGD("store display attribute for given surface type(%d)", surface_type);
7759 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7760 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7761 if (mm_attrs_commit_all(player->attrs)) {
7762 LOGE("failed to commit attribute");
7764 return MM_ERROR_PLAYER_INTERNAL;
7768 return MM_ERROR_NONE;
7771 /* Note : if silent is true, then subtitle would not be displayed. :*/
7773 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7775 mmplayer_t *player = (mmplayer_t *)hplayer;
7779 /* check player handle */
7780 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7782 player->set_mode.subtitle_off = silent;
7784 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7788 return MM_ERROR_NONE;
7792 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7794 mmplayer_gst_element_t *mainbin = NULL;
7795 mmplayer_gst_element_t *textbin = NULL;
7796 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7797 GstState current_state = GST_STATE_VOID_PENDING;
7798 GstState element_state = GST_STATE_VOID_PENDING;
7799 GstState element_pending_state = GST_STATE_VOID_PENDING;
7801 GstEvent *event = NULL;
7802 int result = MM_ERROR_NONE;
7804 GstClock *curr_clock = NULL;
7805 GstClockTime base_time, start_time, curr_time;
7810 /* check player handle */
7811 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7813 player->pipeline->mainbin &&
7814 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7816 mainbin = player->pipeline->mainbin;
7817 textbin = player->pipeline->textbin;
7819 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7821 // sync clock with current pipeline
7822 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7823 curr_time = gst_clock_get_time(curr_clock);
7825 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7826 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7828 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7829 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7831 if (current_state > GST_STATE_READY) {
7832 // sync state with current pipeline
7833 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7834 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7835 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7837 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7838 if (GST_STATE_CHANGE_FAILURE == ret) {
7839 LOGE("fail to state change.");
7840 result = MM_ERROR_PLAYER_INTERNAL;
7844 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7845 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7848 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7849 gst_object_unref(curr_clock);
7852 // seek to current position
7853 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7854 result = MM_ERROR_PLAYER_INVALID_STATE;
7855 LOGE("gst_element_query_position failed, invalid state");
7859 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7860 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);
7862 _mmplayer_gst_send_event_to_sink(player, event);
7864 result = MM_ERROR_PLAYER_INTERNAL;
7865 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7869 /* sync state with current pipeline */
7870 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7871 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7872 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7874 return MM_ERROR_NONE;
7877 /* release text pipeline resource */
7878 player->textsink_linked = 0;
7880 /* release signal */
7881 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7883 /* release textbin with it's childs */
7884 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7885 MMPLAYER_FREEIF(player->pipeline->textbin);
7886 player->pipeline->textbin = NULL;
7888 /* release subtitle elem */
7889 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7890 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7896 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7898 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7899 GstState current_state = GST_STATE_VOID_PENDING;
7901 MMHandleType attrs = 0;
7902 mmplayer_gst_element_t *mainbin = NULL;
7903 mmplayer_gst_element_t *textbin = NULL;
7905 gchar *subtitle_uri = NULL;
7906 int result = MM_ERROR_NONE;
7907 const gchar *charset = NULL;
7911 /* check player handle */
7912 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7914 player->pipeline->mainbin &&
7915 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7916 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7918 mainbin = player->pipeline->mainbin;
7919 textbin = player->pipeline->textbin;
7921 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7922 if (current_state < GST_STATE_READY) {
7923 result = MM_ERROR_PLAYER_INVALID_STATE;
7924 LOGE("Pipeline is not in proper state");
7928 attrs = MMPLAYER_GET_ATTRS(player);
7930 LOGE("cannot get content attribute");
7931 result = MM_ERROR_PLAYER_INTERNAL;
7935 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7936 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7937 LOGE("subtitle uri is not proper filepath");
7938 result = MM_ERROR_PLAYER_INVALID_URI;
7942 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7943 LOGE("failed to get storage info of subtitle path");
7944 result = MM_ERROR_PLAYER_INVALID_URI;
7948 LOGD("old subtitle file path is [%s]", subtitle_uri);
7949 LOGD("new subtitle file path is [%s]", filepath);
7951 if (!strcmp(filepath, subtitle_uri)) {
7952 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7955 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7956 if (mm_attrs_commit_all(player->attrs)) {
7957 LOGE("failed to commit.");
7962 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7963 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7964 player->subtitle_language_list = NULL;
7965 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7967 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7968 if (ret != GST_STATE_CHANGE_SUCCESS) {
7969 LOGE("failed to change state of textbin to READY");
7970 result = MM_ERROR_PLAYER_INTERNAL;
7974 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7975 if (ret != GST_STATE_CHANGE_SUCCESS) {
7976 LOGE("failed to change state of subparse to READY");
7977 result = MM_ERROR_PLAYER_INTERNAL;
7981 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7982 if (ret != GST_STATE_CHANGE_SUCCESS) {
7983 LOGE("failed to change state of filesrc to READY");
7984 result = MM_ERROR_PLAYER_INTERNAL;
7988 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7990 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7992 charset = _mmplayer_get_charset(filepath);
7994 LOGD("detected charset is %s", charset);
7995 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7998 result = _mmplayer_sync_subtitle_pipeline(player);
8005 /* API to switch between external subtitles */
8007 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8009 int result = MM_ERROR_NONE;
8010 mmplayer_t *player = (mmplayer_t *)hplayer;
8015 /* check player handle */
8016 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8018 /* filepath can be null in idle state */
8020 /* check file path */
8021 if ((path = strstr(filepath, "file://")))
8022 result = _mmplayer_exist_file_path(path + 7);
8024 result = _mmplayer_exist_file_path(filepath);
8026 if (result != MM_ERROR_NONE) {
8027 LOGE("invalid subtitle path 0x%X", result);
8028 return result; /* file not found or permission denied */
8032 if (!player->pipeline) {
8034 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8035 if (mm_attrs_commit_all(player->attrs)) {
8036 LOGE("failed to commit"); /* subtitle path will not be created */
8037 return MM_ERROR_PLAYER_INTERNAL;
8040 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8041 /* check filepath */
8042 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8044 if (!__mmplayer_check_subtitle(player)) {
8045 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8046 if (mm_attrs_commit_all(player->attrs)) {
8047 LOGE("failed to commit");
8048 return MM_ERROR_PLAYER_INTERNAL;
8051 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8052 LOGE("fail to create text pipeline");
8053 return MM_ERROR_PLAYER_INTERNAL;
8056 result = _mmplayer_sync_subtitle_pipeline(player);
8058 result = __mmplayer_change_external_subtitle_language(player, filepath);
8061 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8062 player->is_external_subtitle_added_now = TRUE;
8064 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8065 if (!player->subtitle_language_list) {
8066 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8067 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8068 LOGW("subtitle language list is not updated yet");
8070 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8078 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8080 int result = MM_ERROR_NONE;
8081 gchar *change_pad_name = NULL;
8082 GstPad *sinkpad = NULL;
8083 mmplayer_gst_element_t *mainbin = NULL;
8084 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8085 GstCaps *caps = NULL;
8086 gint total_track_num = 0;
8090 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8091 MM_ERROR_PLAYER_NOT_INITIALIZED);
8093 LOGD("Change Track(%d) to %d", type, index);
8095 mainbin = player->pipeline->mainbin;
8097 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8098 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8099 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8100 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8102 /* Changing Video Track is not supported. */
8103 LOGE("Track Type Error");
8107 if (mainbin[elem_idx].gst == NULL) {
8108 result = MM_ERROR_PLAYER_NO_OP;
8109 LOGD("Req track doesn't exist");
8113 total_track_num = player->selector[type].total_track_num;
8114 if (total_track_num <= 0) {
8115 result = MM_ERROR_PLAYER_NO_OP;
8116 LOGD("Language list is not available");
8120 if ((index < 0) || (index >= total_track_num)) {
8121 result = MM_ERROR_INVALID_ARGUMENT;
8122 LOGD("Not a proper index : %d", index);
8126 /*To get the new pad from the selector*/
8127 change_pad_name = g_strdup_printf("sink_%u", index);
8128 if (change_pad_name == NULL) {
8129 result = MM_ERROR_PLAYER_INTERNAL;
8130 LOGD("Pad does not exists");
8134 LOGD("new active pad name: %s", change_pad_name);
8136 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8137 if (sinkpad == NULL) {
8138 LOGD("sinkpad is NULL");
8139 result = MM_ERROR_PLAYER_INTERNAL;
8143 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8144 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8146 caps = gst_pad_get_current_caps(sinkpad);
8147 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8150 gst_object_unref(sinkpad);
8152 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8153 __mmplayer_set_audio_attrs(player, caps);
8156 MMPLAYER_FREEIF(change_pad_name);
8161 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8163 int result = MM_ERROR_NONE;
8164 mmplayer_t *player = NULL;
8165 mmplayer_gst_element_t *mainbin = NULL;
8167 gint current_active_index = 0;
8169 GstState current_state = GST_STATE_VOID_PENDING;
8170 GstEvent *event = NULL;
8175 player = (mmplayer_t *)hplayer;
8176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8178 if (!player->pipeline) {
8179 LOGE("Track %d pre setting -> %d", type, index);
8181 player->selector[type].active_pad_index = index;
8185 mainbin = player->pipeline->mainbin;
8187 current_active_index = player->selector[type].active_pad_index;
8189 /*If index is same as running index no need to change the pad*/
8190 if (current_active_index == index)
8193 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8194 result = MM_ERROR_PLAYER_INVALID_STATE;
8198 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8199 if (current_state < GST_STATE_PAUSED) {
8200 result = MM_ERROR_PLAYER_INVALID_STATE;
8201 LOGW("Pipeline not in porper state");
8205 result = __mmplayer_change_selector_pad(player, type, index);
8206 if (result != MM_ERROR_NONE) {
8207 LOGE("change selector pad error");
8211 player->selector[type].active_pad_index = index;
8213 if (current_state == GST_STATE_PLAYING) {
8214 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8215 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8216 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8218 _mmplayer_gst_send_event_to_sink(player, event);
8220 result = MM_ERROR_PLAYER_INTERNAL;
8230 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8232 mmplayer_t *player = (mmplayer_t *)hplayer;
8236 /* check player handle */
8237 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8239 *silent = player->set_mode.subtitle_off;
8241 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8245 return MM_ERROR_NONE;
8249 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8251 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8252 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8254 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8255 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8259 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8260 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8261 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8262 mmplayer_dump_t *dump_s;
8263 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8264 if (dump_s == NULL) {
8265 LOGE("malloc fail");
8269 dump_s->dump_element_file = NULL;
8270 dump_s->dump_pad = NULL;
8271 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8273 if (dump_s->dump_pad) {
8274 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8275 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]);
8276 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8277 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);
8278 /* add list for removed buffer probe and close FILE */
8279 player->dump_list = g_list_append(player->dump_list, dump_s);
8280 LOGD("%s sink pad added buffer probe for dump", factory_name);
8283 MMPLAYER_FREEIF(dump_s);
8284 LOGE("failed to get %s sink pad added", factory_name);
8291 static GstPadProbeReturn
8292 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8294 FILE *dump_data = (FILE *)u_data;
8296 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8297 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8299 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8301 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8303 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8305 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8307 gst_buffer_unmap(buffer, &probe_info);
8309 return GST_PAD_PROBE_OK;
8313 __mmplayer_release_dump_list(GList *dump_list)
8315 GList *d_list = dump_list;
8320 for (; d_list; d_list = g_list_next(d_list)) {
8321 mmplayer_dump_t *dump_s = d_list->data;
8322 if (dump_s->dump_pad) {
8323 if (dump_s->probe_handle_id)
8324 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8325 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8327 if (dump_s->dump_element_file) {
8328 fclose(dump_s->dump_element_file);
8329 dump_s->dump_element_file = NULL;
8331 MMPLAYER_FREEIF(dump_s);
8333 g_list_free(dump_list);
8338 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8340 mmplayer_t *player = (mmplayer_t *)hplayer;
8344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8345 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8347 *exist = (bool)player->has_closed_caption;
8351 return MM_ERROR_NONE;
8355 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8360 LOGD("unref internal gst buffer %p", buffer);
8362 gst_buffer_unref((GstBuffer *)buffer);
8369 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8371 mmplayer_t *player = (mmplayer_t *)hplayer;
8375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8376 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8378 if (MMPLAYER_IS_STREAMING(player))
8379 *timeout = (int)player->ini.live_state_change_timeout;
8381 *timeout = (int)player->ini.localplayback_state_change_timeout;
8383 LOGD("timeout = %d", *timeout);
8386 return MM_ERROR_NONE;
8390 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8394 MMPLAYER_RETURN_IF_FAIL(player);
8396 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8398 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8399 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8400 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8401 player->storage_info[i].id = -1;
8402 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8404 if (path_type != MMPLAYER_PATH_MAX)
8413 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8415 int ret = MM_ERROR_NONE;
8416 mmplayer_t *player = (mmplayer_t *)hplayer;
8417 MMMessageParamType msg_param = {0, };
8420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8422 LOGW("state changed storage %d:%d", id, state);
8424 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8425 return MM_ERROR_NONE;
8427 /* FIXME: text path should be handled seperately. */
8428 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8429 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8430 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8431 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8432 LOGW("external storage is removed");
8434 if (player->msg_posted == FALSE) {
8435 memset(&msg_param, 0, sizeof(MMMessageParamType));
8436 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8437 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8438 player->msg_posted = TRUE;
8441 /* unrealize the player */
8442 ret = _mmplayer_unrealize(hplayer);
8443 if (ret != MM_ERROR_NONE)
8444 LOGE("failed to unrealize");
8452 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8454 int ret = MM_ERROR_NONE;
8455 mmplayer_t *player = (mmplayer_t *)hplayer;
8456 int idx = 0, total = 0;
8457 gchar *result = NULL, *tmp = NULL;
8460 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8461 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8463 total = *num = g_list_length(player->adaptive_info.var_list);
8465 LOGW("There is no stream variant info.");
8469 result = g_strdup("");
8470 for (idx = 0 ; idx < total ; idx++) {
8471 stream_variant_t *v_data = NULL;
8472 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8475 gchar data[64] = {0};
8476 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8478 tmp = g_strconcat(result, data, NULL);
8482 LOGW("There is no variant data in %d", idx);
8487 *var_info = (char *)result;
8489 LOGD("variant info %d:%s", *num, *var_info);
8495 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8497 int ret = MM_ERROR_NONE;
8498 mmplayer_t *player = (mmplayer_t *)hplayer;
8501 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8503 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8505 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8506 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8507 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8509 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8510 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8511 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8512 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8514 /* FIXME: seek to current position for applying new variant limitation */
8523 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8525 int ret = MM_ERROR_NONE;
8526 mmplayer_t *player = (mmplayer_t *)hplayer;
8529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8530 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8532 *bandwidth = player->adaptive_info.limit.bandwidth;
8533 *width = player->adaptive_info.limit.width;
8534 *height = player->adaptive_info.limit.height;
8536 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8543 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8545 int ret = MM_ERROR_NONE;
8546 mmplayer_t *player = (mmplayer_t *)hplayer;
8549 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8550 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8551 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8553 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8555 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8556 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8557 else /* live case */
8558 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8560 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8567 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8569 #define IDX_FIRST_SW_CODEC 0
8570 mmplayer_t *player = (mmplayer_t *)hplayer;
8571 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8572 MMHandleType attrs = 0;
8575 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8577 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8578 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8579 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8581 switch (stream_type) {
8582 case MM_PLAYER_STREAM_TYPE_AUDIO:
8583 /* to support audio codec selection, codec info have to be added in ini file as below.
8584 audio codec element hw = xxxx
8585 audio codec element sw = avdec */
8586 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8587 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8588 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8589 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8590 LOGE("There is no audio codec info for codec_type %d", codec_type);
8591 return MM_ERROR_PLAYER_NO_OP;
8594 case MM_PLAYER_STREAM_TYPE_VIDEO:
8595 /* to support video codec selection, codec info have to be added in ini file as below.
8596 video codec element hw = omx
8597 video codec element sw = avdec */
8598 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8599 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8600 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8601 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8602 LOGE("There is no video codec info for codec_type %d", codec_type);
8603 return MM_ERROR_PLAYER_NO_OP;
8607 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8608 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8612 LOGD("update %s codec_type to %d", attr_name, codec_type);
8614 attrs = MMPLAYER_GET_ATTRS(player);
8615 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8617 if (mm_attrs_commit_all(player->attrs)) {
8618 LOGE("failed to commit codec_type attributes");
8619 return MM_ERROR_PLAYER_INTERNAL;
8623 return MM_ERROR_NONE;
8627 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8629 mmplayer_t *player = (mmplayer_t *)hplayer;
8630 GstElement *rg_vol_element = NULL;
8634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8636 player->sound.rg_enable = enabled;
8638 /* just hold rgvolume enable value if pipeline is not ready */
8639 if (!player->pipeline || !player->pipeline->audiobin) {
8640 LOGD("pipeline is not ready. holding rgvolume enable value");
8641 return MM_ERROR_NONE;
8644 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8646 if (!rg_vol_element) {
8647 LOGD("rgvolume element is not created");
8648 return MM_ERROR_PLAYER_INTERNAL;
8652 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8654 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8658 return MM_ERROR_NONE;
8662 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8664 mmplayer_t *player = (mmplayer_t *)hplayer;
8665 GstElement *rg_vol_element = NULL;
8666 gboolean enable = FALSE;
8670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8671 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8673 /* just hold enable_rg value if pipeline is not ready */
8674 if (!player->pipeline || !player->pipeline->audiobin) {
8675 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8676 *enabled = player->sound.rg_enable;
8677 return MM_ERROR_NONE;
8680 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8682 if (!rg_vol_element) {
8683 LOGD("rgvolume element is not created");
8684 return MM_ERROR_PLAYER_INTERNAL;
8687 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8688 *enabled = (bool)enable;
8692 return MM_ERROR_NONE;
8696 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8698 mmplayer_t *player = (mmplayer_t *)hplayer;
8699 MMHandleType attrs = 0;
8700 void *handle = NULL;
8701 int ret = MM_ERROR_NONE;
8705 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8707 attrs = MMPLAYER_GET_ATTRS(player);
8708 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8710 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8712 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8713 return MM_ERROR_PLAYER_INTERNAL;
8716 player->video_roi.scale_x = scale_x;
8717 player->video_roi.scale_y = scale_y;
8718 player->video_roi.scale_width = scale_width;
8719 player->video_roi.scale_height = scale_height;
8721 /* check video sinkbin is created */
8722 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8723 return MM_ERROR_NONE;
8725 if (!gst_video_overlay_set_video_roi_area(
8726 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8727 scale_x, scale_y, scale_width, scale_height))
8728 ret = MM_ERROR_PLAYER_INTERNAL;
8730 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8731 scale_x, scale_y, scale_width, scale_height);
8739 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8741 mmplayer_t *player = (mmplayer_t *)hplayer;
8742 int ret = MM_ERROR_NONE;
8746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8747 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8749 *scale_x = player->video_roi.scale_x;
8750 *scale_y = player->video_roi.scale_y;
8751 *scale_width = player->video_roi.scale_width;
8752 *scale_height = player->video_roi.scale_height;
8754 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8755 *scale_x, *scale_y, *scale_width, *scale_height);
8761 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8763 mmplayer_t* player = (mmplayer_t*)hplayer;
8767 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8769 player->client_pid = pid;
8771 LOGD("client pid[%d] %p", pid, player);
8775 return MM_ERROR_NONE;
8779 __mmplayer_update_duration_value(mmplayer_t *player)
8781 gboolean ret = FALSE;
8782 gint64 dur_nsec = 0;
8783 LOGD("try to update duration");
8785 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8786 player->duration = dur_nsec;
8787 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8791 if (player->duration < 0) {
8792 LOGW("duration is Non-Initialized !!!");
8793 player->duration = 0;
8796 /* update streaming service type */
8797 player->streaming_type = _mmplayer_get_stream_service_type(player);
8799 /* check duration is OK */
8800 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8801 /* FIXIT : find another way to get duration here. */
8802 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8808 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8810 /* update audio params
8811 NOTE : We need original audio params and it can be only obtained from src pad of audio
8812 decoder. Below code only valid when we are not using 'resampler' just before
8813 'audioconverter'. */
8814 GstCaps *caps_a = NULL;
8816 gint samplerate = 0, channels = 0;
8817 GstStructure *p = NULL;
8818 GstElement *aconv = NULL;
8820 LOGD("try to update audio attrs");
8822 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8824 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8825 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8826 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8827 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8829 LOGE("there is no audio converter");
8833 pad = gst_element_get_static_pad(aconv, "sink");
8836 LOGW("failed to get pad from audio converter");
8840 caps_a = gst_pad_get_current_caps(pad);
8842 LOGW("not ready to get audio caps");
8843 gst_object_unref(pad);
8847 p = gst_caps_get_structure(caps_a, 0);
8849 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8851 gst_structure_get_int(p, "rate", &samplerate);
8852 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8854 gst_structure_get_int(p, "channels", &channels);
8855 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8857 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8859 gst_caps_unref(caps_a);
8860 gst_object_unref(pad);
8866 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8868 LOGD("try to update video attrs");
8870 GstCaps *caps_v = NULL;
8874 GstStructure *p = NULL;
8876 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8877 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8879 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8881 LOGD("no videosink sink pad");
8885 caps_v = gst_pad_get_current_caps(pad);
8886 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8887 if (!caps_v && player->v_stream_caps) {
8888 caps_v = player->v_stream_caps;
8889 gst_caps_ref(caps_v);
8893 LOGD("no negitiated caps from videosink");
8894 gst_object_unref(pad);
8898 p = gst_caps_get_structure(caps_v, 0);
8899 gst_structure_get_int(p, "width", &width);
8900 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8902 gst_structure_get_int(p, "height", &height);
8903 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8905 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8907 SECURE_LOGD("width : %d height : %d", width, height);
8909 gst_caps_unref(caps_v);
8910 gst_object_unref(pad);
8913 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8914 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8921 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8923 gboolean ret = FALSE;
8924 guint64 data_size = 0;
8928 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8929 if (!player->duration)
8932 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8933 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8934 if (stat(path, &sb) == 0)
8935 data_size = (guint64)sb.st_size;
8937 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8938 data_size = player->http_content_size;
8941 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8944 guint64 bitrate = 0;
8945 guint64 msec_dur = 0;
8947 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8949 bitrate = data_size * 8 * 1000 / msec_dur;
8950 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8951 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8955 LOGD("player duration is less than 0");
8959 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8960 if (player->total_bitrate) {
8961 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8970 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8972 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8973 data->uri_type = uri_type;
8977 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8979 int ret = MM_ERROR_PLAYER_INVALID_URI;
8981 char *buffer = NULL;
8982 char *seperator = strchr(path, ',');
8983 char ext[100] = {0,}, size[100] = {0,};
8986 if ((buffer = strstr(path, "ext="))) {
8987 buffer += strlen("ext=");
8989 if (strlen(buffer)) {
8990 strncpy(ext, buffer, 99);
8992 if ((seperator = strchr(ext, ','))
8993 || (seperator = strchr(ext, ' '))
8994 || (seperator = strchr(ext, '\0'))) {
8995 seperator[0] = '\0';
9000 if ((buffer = strstr(path, "size="))) {
9001 buffer += strlen("size=");
9003 if (strlen(buffer) > 0) {
9004 strncpy(size, buffer, 99);
9006 if ((seperator = strchr(size, ','))
9007 || (seperator = strchr(size, ' '))
9008 || (seperator = strchr(size, '\0'))) {
9009 seperator[0] = '\0';
9012 mem_size = atoi(size);
9017 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9019 if (mem_size && param) {
9020 if (data->input_mem.buf)
9021 free(data->input_mem.buf);
9022 data->input_mem.buf = malloc(mem_size);
9024 if (data->input_mem.buf) {
9025 memcpy(data->input_mem.buf, param, mem_size);
9026 data->input_mem.len = mem_size;
9027 ret = MM_ERROR_NONE;
9029 LOGE("failed to alloc mem %d", mem_size);
9030 ret = MM_ERROR_PLAYER_INTERNAL;
9033 data->input_mem.offset = 0;
9034 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9041 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9043 gchar *location = NULL;
9046 int ret = MM_ERROR_NONE;
9048 if ((path = strstr(uri, "file://"))) {
9049 location = g_filename_from_uri(uri, NULL, &err);
9050 if (!location || (err != NULL)) {
9051 LOGE("Invalid URI '%s' for filesrc: %s", path,
9052 (err != NULL) ? err->message : "unknown error");
9056 MMPLAYER_FREEIF(location);
9058 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9059 return MM_ERROR_PLAYER_INVALID_URI;
9061 LOGD("path from uri: %s", location);
9064 path = (location != NULL) ? (location) : ((char *)uri);
9067 ret = _mmplayer_exist_file_path(path);
9069 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9070 if (ret == MM_ERROR_NONE) {
9071 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9072 if (_mmplayer_is_sdp_file(path)) {
9073 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9074 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9076 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9078 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9079 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9081 LOGE("invalid uri, could not play..");
9082 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9085 MMPLAYER_FREEIF(location);
9090 static mmplayer_video_decoded_data_info_t *
9091 __mmplayer_create_stream_from_pad(GstPad *pad)
9093 GstCaps *caps = NULL;
9094 GstStructure *structure = NULL;
9095 unsigned int fourcc = 0;
9096 const gchar *string_format = NULL;
9097 mmplayer_video_decoded_data_info_t *stream = NULL;
9099 MMPixelFormatType format;
9102 caps = gst_pad_get_current_caps(pad);
9104 LOGE("Caps is NULL.");
9109 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9111 structure = gst_caps_get_structure(caps, 0);
9112 gst_structure_get_int(structure, "width", &width);
9113 gst_structure_get_int(structure, "height", &height);
9114 string_format = gst_structure_get_string(structure, "format");
9117 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9118 format = _mmplayer_get_pixtype(fourcc);
9119 gst_video_info_from_caps(&info, caps);
9120 gst_caps_unref(caps);
9123 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9124 LOGE("Wrong condition!!");
9128 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9130 LOGE("failed to alloc mem for video data");
9134 stream->width = width;
9135 stream->height = height;
9136 stream->format = format;
9137 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9143 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9145 unsigned int pitch = 0;
9146 unsigned int size = 0;
9148 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9151 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9152 bo = gst_tizen_memory_get_bos(mem, index);
9154 stream->bo[index] = tbm_bo_ref(bo);
9156 LOGE("failed to get bo for index %d", index);
9159 for (index = 0; index < stream->plane_num; index++) {
9160 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9161 stream->stride[index] = pitch;
9163 stream->elevation[index] = size / pitch;
9165 stream->elevation[index] = stream->height;
9170 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9172 if (stream->format == MM_PIXEL_FORMAT_I420) {
9173 int ret = TBM_SURFACE_ERROR_NONE;
9174 tbm_surface_h surface;
9175 tbm_surface_info_s info;
9177 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9179 ret = tbm_surface_get_info(surface, &info);
9180 if (ret != TBM_SURFACE_ERROR_NONE) {
9181 tbm_surface_destroy(surface);
9185 tbm_surface_destroy(surface);
9186 stream->stride[0] = info.planes[0].stride;
9187 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9188 stream->stride[1] = info.planes[1].stride;
9189 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9190 stream->stride[2] = info.planes[2].stride;
9191 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9192 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9193 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9194 stream->stride[0] = stream->width * 4;
9195 stream->elevation[0] = stream->height;
9196 stream->bo_size = stream->stride[0] * stream->height;
9198 LOGE("Not support format %d", stream->format);
9206 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9208 tbm_bo_handle thandle;
9210 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9211 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9212 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9216 unsigned char *src = NULL;
9217 unsigned char *dest = NULL;
9218 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9220 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9222 LOGE("fail to gst_memory_map");
9226 if (!mapinfo.data) {
9227 LOGE("data pointer is wrong");
9231 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9232 if (!stream->bo[0]) {
9233 LOGE("Fail to tbm_bo_alloc!!");
9237 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9239 LOGE("thandle pointer is wrong");
9243 if (stream->format == MM_PIXEL_FORMAT_I420) {
9244 src_stride[0] = GST_ROUND_UP_4(stream->width);
9245 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9246 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9247 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9250 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9251 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9253 for (i = 0; i < 3; i++) {
9254 src = mapinfo.data + src_offset[i];
9255 dest = thandle.ptr + dest_offset[i];
9260 for (j = 0; j < stream->height >> k; j++) {
9261 memcpy(dest, src, stream->width>>k);
9262 src += src_stride[i];
9263 dest += stream->stride[i];
9266 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9267 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9269 LOGE("Not support format %d", stream->format);
9273 tbm_bo_unmap(stream->bo[0]);
9274 gst_memory_unmap(mem, &mapinfo);
9280 tbm_bo_unmap(stream->bo[0]);
9283 gst_memory_unmap(mem, &mapinfo);
9289 __mmplayer_set_pause_state(mmplayer_t *player)
9291 if (player->sent_bos)
9294 /* rtsp case, get content attrs by GstMessage */
9295 if (MMPLAYER_IS_RTSP_STREAMING(player))
9298 /* it's first time to update all content attrs. */
9299 _mmplayer_update_content_attrs(player, ATTR_ALL);
9303 __mmplayer_set_playing_state(mmplayer_t *player)
9305 gchar *audio_codec = NULL;
9307 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9308 /* initialize because auto resume is done well. */
9309 player->resumed_by_rewind = FALSE;
9310 player->playback_rate = 1.0;
9313 if (player->sent_bos)
9316 /* try to get content metadata */
9318 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9319 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9320 * legacy mmfw-player api
9322 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9324 if ((player->cmd == MMPLAYER_COMMAND_START)
9325 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9326 __mmplayer_handle_missed_plugin(player);
9329 /* check audio codec field is set or not
9330 * we can get it from typefinder or codec's caps.
9332 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9334 /* The codec format can't be sent for audio only case like amr, mid etc.
9335 * Because, parser don't make related TAG.
9336 * So, if it's not set yet, fill it with found data.
9339 if (g_strrstr(player->type, "audio/midi"))
9340 audio_codec = "MIDI";
9341 else if (g_strrstr(player->type, "audio/x-amr"))
9342 audio_codec = "AMR";
9343 else if (g_strrstr(player->type, "audio/mpeg")
9344 && !g_strrstr(player->type, "mpegversion=(int)1"))
9345 audio_codec = "AAC";
9347 audio_codec = "unknown";
9349 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9351 if (mm_attrs_commit_all(player->attrs))
9352 LOGE("failed to update attributes");
9354 LOGD("set audio codec type with caps");