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;
2527 _mmplayer_add_signal_connection(player,
2529 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2531 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2534 __mmplayer_add_sink(player, sink);
2536 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2537 LOGE("failed to sync state");
2541 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2542 LOGE("failed to sync state");
2550 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2552 gst_object_unref(GST_OBJECT(queue));
2556 gst_object_unref(GST_OBJECT(sink));
2560 gst_object_unref(GST_OBJECT(sinkpad));
2568 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2570 mmplayer_t *player = (mmplayer_t *)data;
2573 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2575 player->no_more_pad = TRUE;
2576 __mmplayer_pipeline_complete(NULL, player);
2583 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2585 #define MAX_PROPS_LEN 128
2586 mmplayer_gst_element_t *audiobin = NULL;
2587 gint latency_mode = 0;
2588 gchar *stream_type = NULL;
2589 gchar *latency = NULL;
2591 gchar stream_props[MAX_PROPS_LEN] = {0,};
2592 GstStructure *props = NULL;
2595 * It should be set after player creation through attribute.
2596 * But, it can not be changed during playing.
2599 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2601 audiobin = player->pipeline->audiobin;
2603 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2604 if (player->sound.mute) {
2605 LOGD("mute enabled");
2606 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2609 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2610 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2613 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2615 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2616 stream_type, stream_id, player->client_pid);
2618 props = gst_structure_from_string(stream_props, NULL);
2619 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2620 LOGI("props result[%s].", stream_props);
2621 gst_structure_free(props);
2623 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2625 switch (latency_mode) {
2626 case AUDIO_LATENCY_MODE_LOW:
2627 latency = g_strndup("low", 3);
2629 case AUDIO_LATENCY_MODE_MID:
2630 latency = g_strndup("mid", 3);
2632 case AUDIO_LATENCY_MODE_HIGH:
2633 latency = g_strndup("high", 4);
2637 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2639 LOGD("audiosink property - latency=%s", latency);
2641 MMPLAYER_FREEIF(latency);
2647 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2649 mmplayer_gst_element_t *audiobin = NULL;
2652 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2654 audiobin = player->pipeline->audiobin;
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2657 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2658 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2660 if (player->video360_yaw_radians <= M_PI &&
2661 player->video360_yaw_radians >= -M_PI &&
2662 player->video360_pitch_radians <= M_PI_2 &&
2663 player->video360_pitch_radians >= -M_PI_2) {
2664 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2665 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2666 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2667 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2668 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2669 "source-orientation-y", player->video360_metadata.init_view_heading,
2670 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2677 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2679 mmplayer_gst_element_t *audiobin = NULL;
2680 GstPad *sink_pad = NULL;
2681 GstCaps *acaps = NULL;
2683 int pitch_control = 0;
2684 double pitch_value = 1.0;
2687 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2688 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2690 audiobin = player->pipeline->audiobin;
2692 LOGD("make element for normal audio playback");
2694 /* audio bin structure for playback. {} means optional.
2695 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2697 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2698 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2701 /* for pitch control */
2702 mm_attrs_multiple_get(player->attrs, NULL,
2703 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2704 MM_PLAYER_PITCH_VALUE, &pitch_value,
2707 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2708 if (pitch_control && (player->videodec_linked == 0)) {
2709 GstElementFactory *factory;
2711 factory = gst_element_factory_find("pitch");
2713 gst_object_unref(factory);
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2722 LOGW("there is no pitch element");
2727 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2729 /* replaygain volume */
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2731 if (player->sound.rg_enable)
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2737 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2739 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2740 /* currently, only openalsink uses volume element */
2741 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2742 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2744 if (player->sound.mute) {
2745 LOGD("mute enabled");
2746 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2750 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2752 /* audio effect element. if audio effect is enabled */
2753 if ((strcmp(player->ini.audioeffect_element, ""))
2755 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2756 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2758 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2760 if ((!player->bypass_audio_effect)
2761 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2762 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2763 if (!_mmplayer_audio_effect_custom_apply(player))
2764 LOGI("apply audio effect(custom) setting success");
2768 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2769 && (player->set_mode.rich_audio)) {
2770 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2774 /* create audio sink */
2775 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2776 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2777 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2779 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2780 if (player->is_360_feature_enabled &&
2781 player->is_content_spherical &&
2783 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2784 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2785 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2787 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2789 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2791 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2792 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2793 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2794 gst_caps_unref(acaps);
2796 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2798 player->is_openal_plugin_used = TRUE;
2800 if (player->is_360_feature_enabled && player->is_content_spherical)
2801 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2802 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2805 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2806 (player->videodec_linked && player->ini.use_system_clock)) {
2807 LOGD("system clock will be used.");
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2811 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2812 __mmplayer_gst_set_pulsesink_property(player);
2813 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2814 __mmplayer_gst_set_openalsink_property(player);
2817 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2818 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2820 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2821 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2822 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2823 gst_object_unref(GST_OBJECT(sink_pad));
2825 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2828 return MM_ERROR_NONE;
2830 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2832 return MM_ERROR_PLAYER_INTERNAL;
2836 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2838 mmplayer_gst_element_t *audiobin = NULL;
2839 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2841 gchar *dst_format = NULL;
2843 int dst_samplerate = 0;
2844 int dst_channels = 0;
2845 GstCaps *caps = NULL;
2846 char *caps_str = NULL;
2849 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2850 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2852 audiobin = player->pipeline->audiobin;
2854 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2856 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2858 [case 1] extract interleave audio pcm without playback
2859 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2860 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2862 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2864 [case 2] deinterleave for each channel without playback
2865 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2866 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2868 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2869 - fakesink (sync or not)
2872 [case 3] [case 1(sync only)] + playback
2873 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2875 * src - ... - tee - queue1 - playback path
2876 - queue2 - [case1 pipeline with sync]
2878 [case 4] [case 2(sync only)] + playback
2879 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2881 * src - ... - tee - queue1 - playback path
2882 - queue2 - [case2 pipeline with sync]
2886 /* 1. create tee and playback path
2887 'tee' should be added at first to copy the decoded stream
2889 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2890 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2891 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2893 /* tee - path 1 : for playback path */
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2895 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2897 /* tee - path 2 : for extract path */
2898 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2899 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2902 /* if there is tee, 'tee - path 2' is linked here */
2904 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2907 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2909 /* 2. decide the extract pcm format */
2910 mm_attrs_multiple_get(player->attrs, NULL,
2911 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2912 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2913 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2916 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2917 dst_format, dst_len, dst_samplerate, dst_channels);
2919 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2920 mm_attrs_multiple_get(player->attrs, NULL,
2921 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2922 "content_audio_samplerate", &dst_samplerate,
2923 "content_audio_channels", &dst_channels,
2926 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2927 dst_format, dst_len, dst_samplerate, dst_channels);
2929 /* If there is no enough information, set it to platform default value. */
2930 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2931 LOGD("set platform default format");
2932 dst_format = DEFAULT_PCM_OUT_FORMAT;
2934 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2935 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2938 /* 3. create capsfilter */
2939 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2940 caps = gst_caps_new_simple("audio/x-raw",
2941 "format", G_TYPE_STRING, dst_format,
2942 "rate", G_TYPE_INT, dst_samplerate,
2943 "channels", G_TYPE_INT, dst_channels,
2946 caps_str = gst_caps_to_string(caps);
2947 LOGD("new caps : %s", caps_str);
2949 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2952 gst_caps_unref(caps);
2953 MMPLAYER_FREEIF(caps_str);
2955 /* 4-1. create deinterleave to extract pcm for each channel */
2956 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2957 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2958 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2960 /* audiosink will be added after getting signal for each channel */
2961 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2962 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2963 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2964 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2965 player->no_more_pad = FALSE;
2967 /* 4-2. create fakesink to extract interlevaed pcm */
2968 LOGD("add audio fakesink for interleaved audio");
2969 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2970 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2971 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2972 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2974 _mmplayer_add_signal_connection(player,
2975 G_OBJECT(audiobin[extract_sink_id].gst),
2976 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2978 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2981 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2985 return MM_ERROR_NONE;
2987 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2989 return MM_ERROR_PLAYER_INTERNAL;
2993 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2995 int ret = MM_ERROR_NONE;
2996 mmplayer_gst_element_t *audiobin = NULL;
2997 GList *element_bucket = NULL;
3000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3001 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3003 audiobin = player->pipeline->audiobin;
3005 if (player->build_audio_offload) { /* skip all the audio filters */
3006 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3008 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3009 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3010 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3012 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3016 /* FIXME: need to mention the supportable condition at API reference */
3017 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3018 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3020 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3022 if (ret != MM_ERROR_NONE)
3025 LOGD("success to make audio bin element");
3026 *bucket = element_bucket;
3029 return MM_ERROR_NONE;
3032 LOGE("failed to make audio bin element");
3033 g_list_free(element_bucket);
3037 return MM_ERROR_PLAYER_INTERNAL;
3041 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3043 mmplayer_gst_element_t *first_element = NULL;
3044 mmplayer_gst_element_t *audiobin = NULL;
3046 GstPad *ghostpad = NULL;
3047 GList *element_bucket = NULL;
3051 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3054 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3056 LOGE("failed to allocate memory for audiobin");
3057 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3061 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3062 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3063 if (!audiobin[MMPLAYER_A_BIN].gst) {
3064 LOGE("failed to create audiobin");
3069 player->pipeline->audiobin = audiobin;
3071 /* create audio filters and audiosink */
3072 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3075 /* adding created elements to bin */
3076 LOGD("adding created elements to bin");
3077 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3080 /* linking elements in the bucket by added order. */
3081 LOGD("Linking elements in the bucket by added order.");
3082 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3085 /* get first element's sinkpad for creating ghostpad */
3086 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3087 if (!first_element) {
3088 LOGE("failed to get first elem");
3092 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3094 LOGE("failed to get pad from first element of audiobin");
3098 ghostpad = gst_ghost_pad_new("sink", pad);
3100 LOGE("failed to create ghostpad");
3104 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3105 LOGE("failed to add ghostpad to audiobin");
3109 gst_object_unref(pad);
3111 g_list_free(element_bucket);
3114 return MM_ERROR_NONE;
3117 LOGD("ERROR : releasing audiobin");
3120 gst_object_unref(GST_OBJECT(pad));
3123 gst_object_unref(GST_OBJECT(ghostpad));
3126 g_list_free(element_bucket);
3128 /* release element which are not added to bin */
3129 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3130 /* NOTE : skip bin */
3131 if (audiobin[i].gst) {
3132 GstObject *parent = NULL;
3133 parent = gst_element_get_parent(audiobin[i].gst);
3136 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3137 audiobin[i].gst = NULL;
3139 gst_object_unref(GST_OBJECT(parent));
3143 /* release audiobin with it's childs */
3144 if (audiobin[MMPLAYER_A_BIN].gst)
3145 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3147 MMPLAYER_FREEIF(audiobin);
3149 player->pipeline->audiobin = NULL;
3151 return MM_ERROR_PLAYER_INTERNAL;
3155 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3157 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3161 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3163 int ret = MM_ERROR_NONE;
3165 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3166 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3168 MMPLAYER_VIDEO_BO_LOCK(player);
3170 if (player->video_bo_list) {
3171 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3172 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3173 if (tmp && tmp->bo == bo) {
3175 LOGD("release bo %p", bo);
3176 tbm_bo_unref(tmp->bo);
3177 MMPLAYER_VIDEO_BO_UNLOCK(player);
3178 MMPLAYER_VIDEO_BO_SIGNAL(player);
3183 /* hw codec is running or the list was reset for DRC. */
3184 LOGW("there is no bo list.");
3186 MMPLAYER_VIDEO_BO_UNLOCK(player);
3188 LOGW("failed to find bo %p", bo);
3193 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3198 MMPLAYER_RETURN_IF_FAIL(player);
3200 MMPLAYER_VIDEO_BO_LOCK(player);
3201 if (player->video_bo_list) {
3202 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3203 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3204 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3207 tbm_bo_unref(tmp->bo);
3211 g_list_free(player->video_bo_list);
3212 player->video_bo_list = NULL;
3214 player->video_bo_size = 0;
3215 MMPLAYER_VIDEO_BO_UNLOCK(player);
3222 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3225 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3226 gboolean ret = TRUE;
3228 /* check DRC, if it is, destroy the prev bo list to create again */
3229 if (player->video_bo_size != size) {
3230 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3231 __mmplayer_video_stream_destroy_bo_list(player);
3232 player->video_bo_size = size;
3235 MMPLAYER_VIDEO_BO_LOCK(player);
3237 if ((!player->video_bo_list) ||
3238 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3240 /* create bo list */
3242 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3244 if (player->video_bo_list) {
3245 /* if bo list did not created all, try it again. */
3246 idx = g_list_length(player->video_bo_list);
3247 LOGD("bo list exist(len: %d)", idx);
3250 for (; idx < player->ini.num_of_video_bo; idx++) {
3251 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3253 LOGE("Fail to alloc bo_info.");
3256 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3258 LOGE("Fail to tbm_bo_alloc.");
3259 MMPLAYER_FREEIF(bo_info);
3262 bo_info->used = FALSE;
3263 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3266 /* update video num buffers */
3267 LOGD("video_num_buffers : %d", idx);
3268 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3269 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3272 MMPLAYER_VIDEO_BO_UNLOCK(player);
3278 /* get bo from list*/
3279 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3280 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3281 if (tmp && (tmp->used == FALSE)) {
3282 LOGD("found bo %p to use", tmp->bo);
3284 MMPLAYER_VIDEO_BO_UNLOCK(player);
3285 return tbm_bo_ref(tmp->bo);
3289 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3290 MMPLAYER_VIDEO_BO_UNLOCK(player);
3294 if (player->ini.video_bo_timeout <= 0) {
3295 MMPLAYER_VIDEO_BO_WAIT(player);
3297 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3298 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3305 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3307 mmplayer_t *player = (mmplayer_t *)data;
3309 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3311 /* send prerolled pkt */
3312 player->video_stream_prerolled = false;
3314 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3316 /* not to send prerolled pkt again */
3317 player->video_stream_prerolled = true;
3321 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3323 mmplayer_t *player = (mmplayer_t *)data;
3324 mmplayer_video_decoded_data_info_t *stream = NULL;
3325 GstMemory *mem = NULL;
3328 MMPLAYER_RETURN_IF_FAIL(player);
3329 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3331 if (player->video_stream_prerolled) {
3332 player->video_stream_prerolled = false;
3333 LOGD("skip the prerolled pkt not to send it again");
3337 /* clear stream data structure */
3338 stream = __mmplayer_create_stream_from_pad(pad);
3340 LOGE("failed to alloc stream");
3344 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3346 /* set size and timestamp */
3347 mem = gst_buffer_peek_memory(buffer, 0);
3348 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3349 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3351 /* check zero-copy */
3352 if (player->set_mode.video_zc &&
3353 player->set_mode.video_export &&
3354 gst_is_tizen_memory(mem)) {
3355 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3356 stream->internal_buffer = gst_buffer_ref(buffer);
3357 } else { /* sw codec */
3358 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3361 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3365 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3366 LOGE("failed to send video decoded data.");
3373 LOGE("release video stream resource.");
3374 if (gst_is_tizen_memory(mem)) {
3376 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3378 tbm_bo_unref(stream->bo[i]);
3381 /* unref gst buffer */
3382 if (stream->internal_buffer)
3383 gst_buffer_unref(stream->internal_buffer);
3386 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3388 MMPLAYER_FREEIF(stream);
3393 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3395 mmplayer_gst_element_t *videobin = NULL;
3398 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3400 videobin = player->pipeline->videobin;
3402 /* Set spatial media metadata and/or user settings to the element.
3404 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3405 "projection-type", player->video360_metadata.projection_type, NULL);
3407 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3408 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3410 if (player->video360_metadata.full_pano_width_pixels &&
3411 player->video360_metadata.full_pano_height_pixels &&
3412 player->video360_metadata.cropped_area_image_width &&
3413 player->video360_metadata.cropped_area_image_height) {
3414 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3415 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3416 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3417 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3418 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3419 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3420 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3424 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3425 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3426 "horizontal-fov", player->video360_horizontal_fov,
3427 "vertical-fov", player->video360_vertical_fov, NULL);
3430 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3431 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3432 "zoom", 1.0f / player->video360_zoom, NULL);
3435 if (player->video360_yaw_radians <= M_PI &&
3436 player->video360_yaw_radians >= -M_PI &&
3437 player->video360_pitch_radians <= M_PI_2 &&
3438 player->video360_pitch_radians >= -M_PI_2) {
3439 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3440 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3441 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3442 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3443 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3444 "pose-yaw", player->video360_metadata.init_view_heading,
3445 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3448 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3449 "passthrough", !player->is_video360_enabled, NULL);
3456 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3458 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3459 GList *element_bucket = NULL;
3462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3464 /* create video360 filter */
3465 if (player->is_360_feature_enabled && player->is_content_spherical) {
3466 LOGD("create video360 element");
3467 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3468 __mmplayer_gst_set_video360_property(player);
3472 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3473 LOGD("skip creating the videoconv and rotator");
3474 return MM_ERROR_NONE;
3477 /* in case of sw codec & overlay surface type, except 360 playback.
3478 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3479 LOGD("create video converter: %s", video_csc);
3480 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3483 *bucket = element_bucket;
3485 return MM_ERROR_NONE;
3487 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3488 g_list_free(element_bucket);
3492 return MM_ERROR_PLAYER_INTERNAL;
3496 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3498 gchar *factory_name = NULL;
3500 switch (surface_type) {
3501 case MM_DISPLAY_SURFACE_OVERLAY:
3502 if (strlen(player->ini.videosink_element_overlay) > 0)
3503 factory_name = player->ini.videosink_element_overlay;
3505 case MM_DISPLAY_SURFACE_REMOTE:
3506 case MM_DISPLAY_SURFACE_NULL:
3507 if (strlen(player->ini.videosink_element_fake) > 0)
3508 factory_name = player->ini.videosink_element_fake;
3511 LOGE("unidentified surface type");
3515 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3516 return factory_name;
3520 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3522 gchar *factory_name = NULL;
3523 mmplayer_gst_element_t *videobin = NULL;
3528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3530 videobin = player->pipeline->videobin;
3531 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3533 attrs = MMPLAYER_GET_ATTRS(player);
3535 LOGE("cannot get content attribute");
3536 return MM_ERROR_PLAYER_INTERNAL;
3539 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3540 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3541 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3543 /* support shard memory with S/W codec on HawkP */
3544 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3545 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3546 "use-tbm", use_tbm, NULL);
3550 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3551 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3554 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3556 LOGD("disable last-sample");
3557 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3560 if (player->set_mode.video_export) {
3562 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3563 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3564 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3566 _mmplayer_add_signal_connection(player,
3567 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3568 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3570 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3573 _mmplayer_add_signal_connection(player,
3574 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3575 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3577 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3581 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3582 return MM_ERROR_PLAYER_INTERNAL;
3584 if (videobin[MMPLAYER_V_SINK].gst) {
3585 GstPad *sink_pad = NULL;
3586 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3588 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3589 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3590 gst_object_unref(GST_OBJECT(sink_pad));
3592 LOGE("failed to get sink pad from videosink");
3596 return MM_ERROR_NONE;
3601 * - video overlay surface(arm/x86) : tizenwlsink
3604 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3607 GList *element_bucket = NULL;
3608 mmplayer_gst_element_t *first_element = NULL;
3609 mmplayer_gst_element_t *videobin = NULL;
3610 gchar *videosink_factory_name = NULL;
3613 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3616 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3618 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3620 player->pipeline->videobin = videobin;
3623 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3624 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3625 if (!videobin[MMPLAYER_V_BIN].gst) {
3626 LOGE("failed to create videobin");
3630 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3633 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3634 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3636 /* additional setting for sink plug-in */
3637 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3638 LOGE("failed to set video property");
3642 /* store it as it's sink element */
3643 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3645 /* adding created elements to bin */
3646 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3647 LOGE("failed to add elements");
3651 /* Linking elements in the bucket by added order */
3652 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3653 LOGE("failed to link elements");
3657 /* get first element's sinkpad for creating ghostpad */
3658 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3659 if (!first_element) {
3660 LOGE("failed to get first element from bucket");
3664 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3666 LOGE("failed to get pad from first element");
3670 /* create ghostpad */
3671 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3672 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3673 LOGE("failed to add ghostpad to videobin");
3676 gst_object_unref(pad);
3678 /* done. free allocated variables */
3679 g_list_free(element_bucket);
3683 return MM_ERROR_NONE;
3686 LOGE("ERROR : releasing videobin");
3687 g_list_free(element_bucket);
3690 gst_object_unref(GST_OBJECT(pad));
3692 /* release videobin with it's childs */
3693 if (videobin[MMPLAYER_V_BIN].gst)
3694 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3696 MMPLAYER_FREEIF(videobin);
3697 player->pipeline->videobin = NULL;
3699 return MM_ERROR_PLAYER_INTERNAL;
3703 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3705 GList *element_bucket = NULL;
3706 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3708 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3709 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3710 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3711 "signal-handoffs", FALSE,
3714 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3715 _mmplayer_add_signal_connection(player,
3716 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3717 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3719 G_CALLBACK(__mmplayer_update_subtitle),
3722 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3723 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3725 if (!player->play_subtitle) {
3726 LOGD("add textbin sink as sink element of whole pipeline.");
3727 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3730 /* adding created elements to bin */
3731 LOGD("adding created elements to bin");
3732 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3733 LOGE("failed to add elements");
3737 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3738 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3739 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3741 /* linking elements in the bucket by added order. */
3742 LOGD("Linking elements in the bucket by added order.");
3743 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3744 LOGE("failed to link elements");
3748 /* done. free allocated variables */
3749 g_list_free(element_bucket);
3751 if (textbin[MMPLAYER_T_QUEUE].gst) {
3753 GstPad *ghostpad = NULL;
3755 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3757 LOGE("failed to get sink pad of text queue");
3761 ghostpad = gst_ghost_pad_new("text_sink", pad);
3762 gst_object_unref(pad);
3765 LOGE("failed to create ghostpad of textbin");
3769 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3770 LOGE("failed to add ghostpad to textbin");
3771 gst_object_unref(ghostpad);
3776 return MM_ERROR_NONE;
3779 g_list_free(element_bucket);
3781 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3782 LOGE("remove textbin sink from sink list");
3783 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3786 /* release element at __mmplayer_gst_create_text_sink_bin */
3787 return MM_ERROR_PLAYER_INTERNAL;
3791 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3793 mmplayer_gst_element_t *textbin = NULL;
3794 GList *element_bucket = NULL;
3795 int surface_type = 0;
3800 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3803 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3805 LOGE("failed to allocate memory for textbin");
3806 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3810 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3811 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3812 if (!textbin[MMPLAYER_T_BIN].gst) {
3813 LOGE("failed to create textbin");
3818 player->pipeline->textbin = textbin;
3821 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3822 LOGD("surface type for subtitle : %d", surface_type);
3823 switch (surface_type) {
3824 case MM_DISPLAY_SURFACE_OVERLAY:
3825 case MM_DISPLAY_SURFACE_NULL:
3826 case MM_DISPLAY_SURFACE_REMOTE:
3827 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3828 LOGE("failed to make plain text elements");
3839 return MM_ERROR_NONE;
3843 LOGD("ERROR : releasing textbin");
3845 g_list_free(element_bucket);
3847 /* release signal */
3848 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3850 /* release element which are not added to bin */
3851 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3852 /* NOTE : skip bin */
3853 if (textbin[i].gst) {
3854 GstObject *parent = NULL;
3855 parent = gst_element_get_parent(textbin[i].gst);
3858 gst_object_unref(GST_OBJECT(textbin[i].gst));
3859 textbin[i].gst = NULL;
3861 gst_object_unref(GST_OBJECT(parent));
3866 /* release textbin with it's childs */
3867 if (textbin[MMPLAYER_T_BIN].gst)
3868 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3870 MMPLAYER_FREEIF(player->pipeline->textbin);
3871 player->pipeline->textbin = NULL;
3874 return MM_ERROR_PLAYER_INTERNAL;
3878 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3880 mmplayer_gst_element_t *mainbin = NULL;
3881 mmplayer_gst_element_t *textbin = NULL;
3882 MMHandleType attrs = 0;
3883 GstElement *subsrc = NULL;
3884 GstElement *subparse = NULL;
3885 gchar *subtitle_uri = NULL;
3886 const gchar *charset = NULL;
3892 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3894 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3896 mainbin = player->pipeline->mainbin;
3898 attrs = MMPLAYER_GET_ATTRS(player);
3900 LOGE("cannot get content attribute");
3901 return MM_ERROR_PLAYER_INTERNAL;
3904 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3905 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3906 LOGE("subtitle uri is not proper filepath.");
3907 return MM_ERROR_PLAYER_INVALID_URI;
3910 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3911 LOGE("failed to get storage info of subtitle path");
3912 return MM_ERROR_PLAYER_INVALID_URI;
3915 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3917 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3918 player->subtitle_language_list = NULL;
3919 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3921 /* create the subtitle source */
3922 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3924 LOGE("failed to create filesrc element");
3927 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3929 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3930 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3932 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3933 LOGW("failed to add queue");
3934 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3935 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3936 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3941 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3943 LOGE("failed to create subparse element");
3947 charset = _mmplayer_get_charset(subtitle_uri);
3949 LOGD("detected charset is %s", charset);
3950 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3953 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3954 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3956 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3957 LOGW("failed to add subparse");
3958 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3959 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3960 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3964 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3965 LOGW("failed to link subsrc and subparse");
3969 player->play_subtitle = TRUE;
3970 player->adjust_subtitle_pos = 0;
3972 LOGD("play subtitle using subtitle file");
3974 if (player->pipeline->textbin == NULL) {
3975 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3976 LOGE("failed to create text sink bin. continuing without text");
3980 textbin = player->pipeline->textbin;
3982 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3983 LOGW("failed to add textbin");
3985 /* release signal */
3986 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3988 /* release textbin with it's childs */
3989 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3990 MMPLAYER_FREEIF(player->pipeline->textbin);
3991 player->pipeline->textbin = textbin = NULL;
3995 LOGD("link text input selector and textbin ghost pad");
3997 player->textsink_linked = 1;
3998 player->external_text_idx = 0;
3999 LOGI("textsink is linked");
4001 textbin = player->pipeline->textbin;
4002 LOGD("text bin has been created. reuse it.");
4003 player->external_text_idx = 1;
4006 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4007 LOGW("failed to link subparse and textbin");
4011 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4013 LOGE("failed to get sink pad from textsink to probe data");
4017 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4018 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4020 gst_object_unref(pad);
4023 /* create dot. for debugging */
4024 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4027 return MM_ERROR_NONE;
4030 /* release text pipeline resource */
4031 player->textsink_linked = 0;
4033 /* release signal */
4034 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4036 if (player->pipeline->textbin) {
4037 LOGE("remove textbin");
4039 /* release textbin with it's childs */
4040 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4041 MMPLAYER_FREEIF(player->pipeline->textbin);
4042 player->pipeline->textbin = NULL;
4046 /* release subtitle elem */
4047 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4048 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4050 return MM_ERROR_PLAYER_INTERNAL;
4054 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4056 mmplayer_t *player = (mmplayer_t *)data;
4057 MMMessageParamType msg = {0, };
4058 GstClockTime duration = 0;
4059 gpointer text = NULL;
4060 guint text_size = 0;
4061 gboolean ret = TRUE;
4062 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4066 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4067 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4069 if (player->is_subtitle_force_drop) {
4070 LOGW("subtitle is dropped forcedly.");
4074 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4075 text = mapinfo.data;
4076 text_size = mapinfo.size;
4078 if (player->set_mode.subtitle_off) {
4079 LOGD("subtitle is OFF.");
4083 if (!text || (text_size == 0)) {
4084 LOGD("There is no subtitle to be displayed.");
4088 msg.data = (void *)text;
4090 duration = GST_BUFFER_DURATION(buffer);
4092 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4093 if (player->duration > GST_BUFFER_PTS(buffer))
4094 duration = player->duration - GST_BUFFER_PTS(buffer);
4097 LOGI("subtitle duration is invalid, subtitle duration change "
4098 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4100 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4102 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4104 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4105 gst_buffer_unmap(buffer, &mapinfo);
4112 static GstPadProbeReturn
4113 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4115 mmplayer_t *player = (mmplayer_t *)u_data;
4116 GstClockTime cur_timestamp = 0;
4117 gint64 adjusted_timestamp = 0;
4118 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4120 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4122 if (player->set_mode.subtitle_off) {
4123 LOGD("subtitle is OFF.");
4127 if (player->adjust_subtitle_pos == 0) {
4128 LOGD("nothing to do");
4132 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4133 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4135 if (adjusted_timestamp < 0) {
4136 LOGD("adjusted_timestamp under zero");
4141 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4142 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4143 GST_TIME_ARGS(cur_timestamp),
4144 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4146 return GST_PAD_PROBE_OK;
4150 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4154 /* check player and subtitlebin are created */
4155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4156 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4158 if (position == 0) {
4159 LOGD("nothing to do");
4161 return MM_ERROR_NONE;
4164 /* check current postion */
4165 player->adjust_subtitle_pos = position;
4167 LOGD("save adjust_subtitle_pos in player");
4171 return MM_ERROR_NONE;
4175 * This function is to create audio or video pipeline for playing.
4177 * @param player [in] handle of player
4179 * @return This function returns zero on success.
4184 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4186 int ret = MM_ERROR_NONE;
4187 mmplayer_gst_element_t *mainbin = NULL;
4188 MMHandleType attrs = 0;
4191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4193 /* get profile attribute */
4194 attrs = MMPLAYER_GET_ATTRS(player);
4196 LOGE("failed to get content attribute");
4200 /* create pipeline handles */
4201 if (player->pipeline) {
4202 LOGE("pipeline should be released before create new one");
4206 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4207 if (player->pipeline == NULL)
4210 /* create mainbin */
4211 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4212 if (mainbin == NULL)
4215 /* create pipeline */
4216 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4217 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4218 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4219 LOGE("failed to create pipeline");
4224 player->pipeline->mainbin = mainbin;
4226 /* create the source and decoder elements */
4227 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4228 ret = _mmplayer_gst_build_es_pipeline(player);
4230 ret = _mmplayer_gst_build_pipeline(player);
4232 if (ret != MM_ERROR_NONE) {
4233 LOGE("failed to create some elements");
4237 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4238 if (__mmplayer_check_subtitle(player)
4239 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4240 LOGE("failed to create text pipeline");
4243 ret = _mmplayer_gst_add_bus_watch(player);
4244 if (ret != MM_ERROR_NONE) {
4245 LOGE("failed to add bus watch");
4250 return MM_ERROR_NONE;
4253 __mmplayer_gst_destroy_pipeline(player);
4254 return MM_ERROR_PLAYER_INTERNAL;
4258 __mmplayer_reset_gapless_state(mmplayer_t *player)
4261 MMPLAYER_RETURN_IF_FAIL(player
4263 && player->pipeline->audiobin
4264 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4266 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4273 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4276 int ret = MM_ERROR_NONE;
4280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4282 /* cleanup stuffs */
4283 MMPLAYER_FREEIF(player->type);
4284 player->no_more_pad = FALSE;
4285 player->num_dynamic_pad = 0;
4286 player->demux_pad_index = 0;
4288 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4289 player->subtitle_language_list = NULL;
4290 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4292 __mmplayer_reset_gapless_state(player);
4294 if (player->streamer) {
4295 _mm_player_streaming_initialize(player->streamer, FALSE);
4296 _mm_player_streaming_destroy(player->streamer);
4297 player->streamer = NULL;
4300 /* cleanup unlinked mime type */
4301 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4302 MMPLAYER_FREEIF(player->unlinked_video_mime);
4303 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4305 /* cleanup running stuffs */
4306 _mmplayer_cancel_eos_timer(player);
4308 /* cleanup gst stuffs */
4309 if (player->pipeline) {
4310 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4311 GstTagList *tag_list = player->pipeline->tag_list;
4313 /* first we need to disconnect all signal hander */
4314 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4317 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4318 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4319 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4320 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4321 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4322 gst_object_unref(bus);
4324 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4325 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4326 if (ret != MM_ERROR_NONE) {
4327 LOGE("fail to change state to NULL");
4328 return MM_ERROR_PLAYER_INTERNAL;
4331 LOGW("succeeded in changing state to NULL");
4333 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4336 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4337 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4339 /* free avsysaudiosink
4340 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4341 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4343 MMPLAYER_FREEIF(audiobin);
4344 MMPLAYER_FREEIF(videobin);
4345 MMPLAYER_FREEIF(textbin);
4346 MMPLAYER_FREEIF(mainbin);
4350 gst_tag_list_unref(tag_list);
4352 MMPLAYER_FREEIF(player->pipeline);
4354 MMPLAYER_FREEIF(player->album_art);
4356 if (player->v_stream_caps) {
4357 gst_caps_unref(player->v_stream_caps);
4358 player->v_stream_caps = NULL;
4361 if (player->a_stream_caps) {
4362 gst_caps_unref(player->a_stream_caps);
4363 player->a_stream_caps = NULL;
4366 if (player->s_stream_caps) {
4367 gst_caps_unref(player->s_stream_caps);
4368 player->s_stream_caps = NULL;
4370 _mmplayer_track_destroy(player);
4372 if (player->sink_elements)
4373 g_list_free(player->sink_elements);
4374 player->sink_elements = NULL;
4376 if (player->bufmgr) {
4377 tbm_bufmgr_deinit(player->bufmgr);
4378 player->bufmgr = NULL;
4381 LOGW("finished destroy pipeline");
4389 __mmplayer_gst_realize(mmplayer_t *player)
4392 int ret = MM_ERROR_NONE;
4396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4398 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4400 ret = __mmplayer_gst_create_pipeline(player);
4402 LOGE("failed to create pipeline");
4406 /* set pipeline state to READY */
4407 /* NOTE : state change to READY must be performed sync. */
4408 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4409 ret = _mmplayer_gst_set_state(player,
4410 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4412 if (ret != MM_ERROR_NONE) {
4413 /* return error if failed to set state */
4414 LOGE("failed to set READY state");
4418 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4420 /* create dot before error-return. for debugging */
4421 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4429 __mmplayer_gst_unrealize(mmplayer_t *player)
4431 int ret = MM_ERROR_NONE;
4435 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4437 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4438 MMPLAYER_PRINT_STATE(player);
4440 /* release miscellaneous information */
4441 __mmplayer_release_misc(player);
4443 /* destroy pipeline */
4444 ret = __mmplayer_gst_destroy_pipeline(player);
4445 if (ret != MM_ERROR_NONE) {
4446 LOGE("failed to destory pipeline");
4450 /* release miscellaneous information.
4451 these info needs to be released after pipeline is destroyed. */
4452 __mmplayer_release_misc_post(player);
4454 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4462 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4467 LOGW("set_message_callback is called with invalid player handle");
4468 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4471 player->msg_cb = callback;
4472 player->msg_cb_param = user_param;
4474 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4478 return MM_ERROR_NONE;
4482 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4484 int ret = MM_ERROR_NONE;
4489 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4490 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4491 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4493 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4495 if (strstr(uri, "es_buff://")) {
4496 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4497 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4498 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4499 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4501 tmp = g_ascii_strdown(uri, strlen(uri));
4502 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4503 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4505 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4507 } else if (strstr(uri, "mms://")) {
4508 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4509 } else if ((path = strstr(uri, "mem://"))) {
4510 ret = __mmplayer_set_mem_uri(data, path, param);
4512 ret = __mmplayer_set_file_uri(data, uri);
4515 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4516 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4517 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4518 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4520 /* dump parse result */
4521 SECURE_LOGW("incoming uri : %s", uri);
4522 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4523 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4531 __mmplayer_can_do_interrupt(mmplayer_t *player)
4533 if (!player || !player->pipeline || !player->attrs) {
4534 LOGW("not initialized");
4538 if (player->audio_decoded_cb) {
4539 LOGW("not support in pcm extraction mode");
4543 /* check if seeking */
4544 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4545 MMMessageParamType msg_param;
4546 memset(&msg_param, 0, sizeof(MMMessageParamType));
4547 msg_param.code = MM_ERROR_PLAYER_SEEK;
4548 player->seek_state = MMPLAYER_SEEK_NONE;
4549 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4553 /* check other thread */
4554 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4555 LOGW("locked already, cmd state : %d", player->cmd);
4557 /* check application command */
4558 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4559 LOGW("playing.. should wait cmd lock then, will be interrupted");
4561 /* lock will be released at mrp_resource_release_cb() */
4562 MMPLAYER_CMD_LOCK(player);
4565 LOGW("nothing to do");
4568 LOGW("can interrupt immediately");
4572 FAILED: /* with CMD UNLOCKED */
4575 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4580 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4583 mmplayer_t *player = NULL;
4584 MMMessageParamType msg = {0, };
4586 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4591 LOGE("user_data is null");
4594 player = (mmplayer_t *)user_data;
4596 if (!__mmplayer_can_do_interrupt(player)) {
4597 LOGW("no need to interrupt, so leave");
4598 /* FIXME: there is no way to avoid releasing resource. */
4602 player->interrupted_by_resource = TRUE;
4604 /* get last play position */
4605 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4606 msg.union_type = MM_MSG_UNION_TIME;
4607 msg.time.elapsed = pos;
4608 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4610 LOGW("failed to get play position.");
4613 LOGD("video resource conflict so, resource will be freed by unrealizing");
4614 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4615 LOGE("failed to unrealize");
4617 /* lock is called in __mmplayer_can_do_interrupt() */
4618 MMPLAYER_CMD_UNLOCK(player);
4620 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4621 player->hw_resource[res_idx] = NULL;
4625 return TRUE; /* release all the resources */
4629 __mmplayer_initialize_video_roi(mmplayer_t *player)
4631 player->video_roi.scale_x = 0.0;
4632 player->video_roi.scale_y = 0.0;
4633 player->video_roi.scale_width = 1.0;
4634 player->video_roi.scale_height = 1.0;
4638 _mmplayer_create_player(MMHandleType handle)
4640 int ret = MM_ERROR_PLAYER_INTERNAL;
4641 bool enabled = false;
4643 mmplayer_t *player = MM_PLAYER_CAST(handle);
4647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4649 /* initialize player state */
4650 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4651 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4652 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4653 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4655 /* check current state */
4656 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4658 /* construct attributes */
4659 player->attrs = _mmplayer_construct_attribute(handle);
4661 if (!player->attrs) {
4662 LOGE("Failed to construct attributes");
4666 /* initialize gstreamer with configured parameter */
4667 if (!__mmplayer_init_gstreamer(player)) {
4668 LOGE("Initializing gstreamer failed");
4669 _mmplayer_deconstruct_attribute(handle);
4673 /* create lock. note that g_tread_init() has already called in gst_init() */
4674 g_mutex_init(&player->fsink_lock);
4676 /* create update tag lock */
4677 g_mutex_init(&player->update_tag_lock);
4679 /* create gapless play mutex */
4680 g_mutex_init(&player->gapless_play_thread_mutex);
4682 /* create gapless play cond */
4683 g_cond_init(&player->gapless_play_thread_cond);
4685 /* create gapless play thread */
4686 player->gapless_play_thread =
4687 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4688 if (!player->gapless_play_thread) {
4689 LOGE("failed to create gapless play thread");
4690 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4691 g_mutex_clear(&player->gapless_play_thread_mutex);
4692 g_cond_clear(&player->gapless_play_thread_cond);
4696 player->bus_msg_q = g_queue_new();
4697 if (!player->bus_msg_q) {
4698 LOGE("failed to create queue for bus_msg");
4699 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4703 ret = _mmplayer_initialize_video_capture(player);
4704 if (ret != MM_ERROR_NONE) {
4705 LOGE("failed to initialize video capture");
4709 /* initialize resource manager */
4710 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4711 __resource_release_cb, player, &player->resource_manager)
4712 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4713 LOGE("failed to initialize resource manager");
4714 ret = MM_ERROR_PLAYER_INTERNAL;
4718 /* create video bo lock and cond */
4719 g_mutex_init(&player->video_bo_mutex);
4720 g_cond_init(&player->video_bo_cond);
4722 /* create subtitle info lock and cond */
4723 g_mutex_init(&player->subtitle_info_mutex);
4724 g_cond_init(&player->subtitle_info_cond);
4726 player->streaming_type = STREAMING_SERVICE_NONE;
4728 /* give default value of audio effect setting */
4729 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4730 player->sound.rg_enable = false;
4731 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4733 player->play_subtitle = FALSE;
4734 player->has_closed_caption = FALSE;
4735 player->pending_resume = FALSE;
4736 if (player->ini.dump_element_keyword[0][0] == '\0')
4737 player->ini.set_dump_element_flag = FALSE;
4739 player->ini.set_dump_element_flag = TRUE;
4741 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4742 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4743 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4745 /* Set video360 settings to their defaults for just-created player.
4748 player->is_360_feature_enabled = FALSE;
4749 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4750 LOGI("spherical feature info: %d", enabled);
4752 player->is_360_feature_enabled = TRUE;
4754 LOGE("failed to get spherical feature info");
4757 player->is_content_spherical = FALSE;
4758 player->is_video360_enabled = TRUE;
4759 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4760 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4761 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4762 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4763 player->video360_zoom = 1.0f;
4764 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4765 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4767 __mmplayer_initialize_video_roi(player);
4769 /* set player state to null */
4770 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4771 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4775 return MM_ERROR_NONE;
4779 g_mutex_clear(&player->fsink_lock);
4780 /* free update tag lock */
4781 g_mutex_clear(&player->update_tag_lock);
4782 g_queue_free(player->bus_msg_q);
4783 player->bus_msg_q = NULL;
4784 /* free gapless play thread */
4785 if (player->gapless_play_thread) {
4786 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4787 player->gapless_play_thread_exit = TRUE;
4788 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4789 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4791 g_thread_join(player->gapless_play_thread);
4792 player->gapless_play_thread = NULL;
4794 g_mutex_clear(&player->gapless_play_thread_mutex);
4795 g_cond_clear(&player->gapless_play_thread_cond);
4798 /* release attributes */
4799 _mmplayer_deconstruct_attribute(handle);
4807 __mmplayer_init_gstreamer(mmplayer_t *player)
4809 static gboolean initialized = FALSE;
4810 static const int max_argc = 50;
4812 gchar **argv = NULL;
4813 gchar **argv2 = NULL;
4819 LOGD("gstreamer already initialized.");
4824 argc = malloc(sizeof(int));
4825 argv = malloc(sizeof(gchar *) * max_argc);
4826 argv2 = malloc(sizeof(gchar *) * max_argc);
4828 if (!argc || !argv || !argv2)
4831 memset(argv, 0, sizeof(gchar *) * max_argc);
4832 memset(argv2, 0, sizeof(gchar *) * max_argc);
4836 argv[0] = g_strdup("mmplayer");
4839 for (i = 0; i < 5; i++) {
4840 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4841 if (strlen(player->ini.gst_param[i]) > 0) {
4842 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4847 /* we would not do fork for scanning plugins */
4848 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4851 /* check disable registry scan */
4852 if (player->ini.skip_rescan) {
4853 argv[*argc] = g_strdup("--gst-disable-registry-update");
4857 /* check disable segtrap */
4858 if (player->ini.disable_segtrap) {
4859 argv[*argc] = g_strdup("--gst-disable-segtrap");
4863 LOGD("initializing gstreamer with following parameter");
4864 LOGD("argc : %d", *argc);
4867 for (i = 0; i < arg_count; i++) {
4869 LOGD("argv[%d] : %s", i, argv2[i]);
4872 /* initializing gstreamer */
4873 if (!gst_init_check(argc, &argv, &err)) {
4874 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4881 for (i = 0; i < arg_count; i++) {
4883 LOGD("release - argv[%d] : %s", i, argv2[i]);
4885 MMPLAYER_FREEIF(argv2[i]);
4888 MMPLAYER_FREEIF(argv);
4889 MMPLAYER_FREEIF(argv2);
4890 MMPLAYER_FREEIF(argc);
4900 for (i = 0; i < arg_count; i++) {
4901 LOGD("free[%d] : %s", i, argv2[i]);
4902 MMPLAYER_FREEIF(argv2[i]);
4905 MMPLAYER_FREEIF(argv);
4906 MMPLAYER_FREEIF(argv2);
4907 MMPLAYER_FREEIF(argc);
4913 __mmplayer_check_async_state_transition(mmplayer_t *player)
4915 GstState element_state = GST_STATE_VOID_PENDING;
4916 GstState element_pending_state = GST_STATE_VOID_PENDING;
4917 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4918 GstElement *element = NULL;
4919 gboolean async = FALSE;
4921 /* check player handle */
4922 MMPLAYER_RETURN_IF_FAIL(player &&
4924 player->pipeline->mainbin &&
4925 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4928 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4930 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4931 LOGD("don't need to check the pipeline state");
4935 MMPLAYER_PRINT_STATE(player);
4937 /* wait for state transition */
4938 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4939 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4941 if (ret == GST_STATE_CHANGE_FAILURE) {
4942 LOGE(" [%s] state : %s pending : %s",
4943 GST_ELEMENT_NAME(element),
4944 gst_element_state_get_name(element_state),
4945 gst_element_state_get_name(element_pending_state));
4947 /* dump state of all element */
4948 _mmplayer_dump_pipeline_state(player);
4953 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4958 _mmplayer_destroy(MMHandleType handle)
4960 mmplayer_t *player = MM_PLAYER_CAST(handle);
4964 /* check player handle */
4965 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4967 /* destroy can called at anytime */
4968 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4970 /* check async state transition */
4971 __mmplayer_check_async_state_transition(player);
4973 /* release gapless play thread */
4974 if (player->gapless_play_thread) {
4975 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4976 player->gapless_play_thread_exit = TRUE;
4977 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4978 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4980 LOGD("waitting for gapless play thread exit");
4981 g_thread_join(player->gapless_play_thread);
4982 g_mutex_clear(&player->gapless_play_thread_mutex);
4983 g_cond_clear(&player->gapless_play_thread_cond);
4984 LOGD("gapless play thread released");
4987 _mmplayer_release_video_capture(player);
4989 /* de-initialize resource manager */
4990 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4991 player->resource_manager))
4992 LOGE("failed to deinitialize resource manager");
4994 /* release pipeline */
4995 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4996 LOGE("failed to destory pipeline");
4997 return MM_ERROR_PLAYER_INTERNAL;
5000 g_queue_free(player->bus_msg_q);
5002 /* release subtitle info lock and cond */
5003 g_mutex_clear(&player->subtitle_info_mutex);
5004 g_cond_clear(&player->subtitle_info_cond);
5006 __mmplayer_release_dump_list(player->dump_list);
5008 /* release miscellaneous information */
5009 __mmplayer_release_misc(player);
5011 /* release miscellaneous information.
5012 these info needs to be released after pipeline is destroyed. */
5013 __mmplayer_release_misc_post(player);
5015 /* release attributes */
5016 _mmplayer_deconstruct_attribute(handle);
5019 g_mutex_clear(&player->fsink_lock);
5022 g_mutex_clear(&player->update_tag_lock);
5024 /* release video bo lock and cond */
5025 g_mutex_clear(&player->video_bo_mutex);
5026 g_cond_clear(&player->video_bo_cond);
5030 return MM_ERROR_NONE;
5034 _mmplayer_realize(MMHandleType hplayer)
5036 mmplayer_t *player = (mmplayer_t *)hplayer;
5039 MMHandleType attrs = 0;
5040 int ret = MM_ERROR_NONE;
5044 /* check player handle */
5045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047 /* check current state */
5048 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5050 attrs = MMPLAYER_GET_ATTRS(player);
5052 LOGE("fail to get attributes.");
5053 return MM_ERROR_PLAYER_INTERNAL;
5055 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5056 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5058 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5059 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5061 if (ret != MM_ERROR_NONE) {
5062 LOGE("failed to parse profile");
5067 if (uri && (strstr(uri, "es_buff://"))) {
5068 if (strstr(uri, "es_buff://push_mode"))
5069 player->es_player_push_mode = TRUE;
5071 player->es_player_push_mode = FALSE;
5074 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5075 LOGW("mms protocol is not supported format.");
5076 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5079 if (MMPLAYER_IS_STREAMING(player))
5080 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5082 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5084 player->smooth_streaming = FALSE;
5085 player->videodec_linked = 0;
5086 player->audiodec_linked = 0;
5087 player->textsink_linked = 0;
5088 player->is_external_subtitle_present = FALSE;
5089 player->is_external_subtitle_added_now = FALSE;
5090 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5091 player->video360_metadata.is_spherical = -1;
5092 player->is_openal_plugin_used = FALSE;
5093 player->demux_pad_index = 0;
5094 player->subtitle_language_list = NULL;
5095 player->is_subtitle_force_drop = FALSE;
5097 _mmplayer_track_initialize(player);
5098 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5100 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5101 gint prebuffer_ms = 0, rebuffer_ms = 0;
5103 player->streamer = _mm_player_streaming_create();
5104 _mm_player_streaming_initialize(player->streamer, TRUE);
5106 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5107 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5109 if (prebuffer_ms > 0) {
5110 prebuffer_ms = MAX(prebuffer_ms, 1000);
5111 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5114 if (rebuffer_ms > 0) {
5115 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5116 rebuffer_ms = MAX(rebuffer_ms, 1000);
5117 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5120 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5121 player->streamer->buffering_req.rebuffer_time);
5124 /* realize pipeline */
5125 ret = __mmplayer_gst_realize(player);
5126 if (ret != MM_ERROR_NONE)
5127 LOGE("fail to realize the player.");
5129 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5137 _mmplayer_unrealize(MMHandleType hplayer)
5139 mmplayer_t *player = (mmplayer_t *)hplayer;
5140 int ret = MM_ERROR_NONE;
5144 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5146 MMPLAYER_CMD_UNLOCK(player);
5147 /* destroy the gst bus msg thread which is created during realize.
5148 this funct have to be called before getting cmd lock. */
5149 _mmplayer_bus_msg_thread_destroy(player);
5150 MMPLAYER_CMD_LOCK(player);
5152 /* check current state */
5153 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5155 /* check async state transition */
5156 __mmplayer_check_async_state_transition(player);
5158 /* unrealize pipeline */
5159 ret = __mmplayer_gst_unrealize(player);
5161 if (!player->interrupted_by_resource) {
5162 int rm_ret = MM_ERROR_NONE;
5163 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5165 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5166 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5167 if (rm_ret != MM_ERROR_NONE)
5168 LOGE("failed to release [%d] resources", res_idx);
5177 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5179 mmplayer_t *player = (mmplayer_t *)hplayer;
5181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5183 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5187 _mmplayer_get_state(MMHandleType hplayer, int *state)
5189 mmplayer_t *player = (mmplayer_t *)hplayer;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5193 *state = MMPLAYER_CURRENT_STATE(player);
5195 return MM_ERROR_NONE;
5199 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5201 GstElement *vol_element = NULL;
5202 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5208 /* check pipeline handle */
5209 if (!player->pipeline || !player->pipeline->audiobin) {
5210 LOGD("'%s' will be applied when audiobin is created", prop_name);
5212 /* NOTE : stored value will be used in create_audiobin
5213 * returning MM_ERROR_NONE here makes application to able to
5214 * set audio volume or mute at anytime.
5216 return MM_ERROR_NONE;
5219 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5220 volume_elem_id = MMPLAYER_A_SINK;
5222 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5224 LOGE("failed to get vol element %d", volume_elem_id);
5225 return MM_ERROR_PLAYER_INTERNAL;
5228 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5230 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5231 LOGE("there is no '%s' property", prop_name);
5232 return MM_ERROR_PLAYER_INTERNAL;
5235 if (!strcmp(prop_name, "volume")) {
5236 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5237 } else if (!strcmp(prop_name, "mute")) {
5238 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5240 LOGE("invalid property %s", prop_name);
5241 return MM_ERROR_PLAYER_INTERNAL;
5244 return MM_ERROR_NONE;
5248 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5250 int ret = MM_ERROR_NONE;
5251 mmplayer_t *player = (mmplayer_t *)hplayer;
5254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5256 LOGD("volume = %f", volume);
5258 /* invalid factor range or not */
5259 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5260 LOGE("Invalid volume value");
5261 return MM_ERROR_INVALID_ARGUMENT;
5264 player->sound.volume = volume;
5266 ret = __mmplayer_gst_set_volume_property(player, "volume");
5273 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5282 *volume = player->sound.volume;
5284 LOGD("current vol = %f", *volume);
5287 return MM_ERROR_NONE;
5291 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5293 int ret = MM_ERROR_NONE;
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5299 LOGD("mute = %d", mute);
5301 player->sound.mute = mute;
5303 ret = __mmplayer_gst_set_volume_property(player, "mute");
5310 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5312 mmplayer_t *player = (mmplayer_t *)hplayer;
5316 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5317 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5319 *mute = player->sound.mute;
5321 LOGD("current mute = %d", *mute);
5325 return MM_ERROR_NONE;
5329 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5331 mmplayer_t *player = (mmplayer_t *)hplayer;
5335 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5337 player->audio_stream_changed_cb = callback;
5338 player->audio_stream_changed_cb_user_param = user_param;
5339 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5343 return MM_ERROR_NONE;
5347 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5349 mmplayer_t *player = (mmplayer_t *)hplayer;
5353 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5355 player->audio_decoded_cb = callback;
5356 player->audio_decoded_cb_user_param = user_param;
5357 player->audio_extract_opt = opt;
5358 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5362 return MM_ERROR_NONE;
5366 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5368 mmplayer_t *player = (mmplayer_t *)hplayer;
5372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5374 if (callback && !player->bufmgr)
5375 player->bufmgr = tbm_bufmgr_init(-1);
5377 player->set_mode.video_export = (callback) ? true : false;
5378 player->video_decoded_cb = callback;
5379 player->video_decoded_cb_user_param = user_param;
5381 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5385 return MM_ERROR_NONE;
5389 _mmplayer_start(MMHandleType hplayer)
5391 mmplayer_t *player = (mmplayer_t *)hplayer;
5392 gint ret = MM_ERROR_NONE;
5396 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5398 /* check current state */
5399 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5401 /* start pipeline */
5402 ret = _mmplayer_gst_start(player);
5403 if (ret != MM_ERROR_NONE)
5404 LOGE("failed to start player.");
5406 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5407 LOGD("force playing start even during buffering");
5408 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5416 /* NOTE: post "not supported codec message" to application
5417 * when one codec is not found during AUTOPLUGGING in MSL.
5418 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5419 * And, if any codec is not found, don't send message here.
5420 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5423 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5425 MMMessageParamType msg_param;
5426 memset(&msg_param, 0, sizeof(MMMessageParamType));
5427 gboolean post_msg_direct = FALSE;
5431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5433 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5434 player->not_supported_codec, player->can_support_codec);
5436 if (player->not_found_demuxer) {
5437 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5438 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5440 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5441 MMPLAYER_FREEIF(msg_param.data);
5443 return MM_ERROR_NONE;
5446 if (player->not_supported_codec) {
5447 if (player->can_support_codec) {
5448 // There is one codec to play
5449 post_msg_direct = TRUE;
5451 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5452 post_msg_direct = TRUE;
5455 if (post_msg_direct) {
5456 MMMessageParamType msg_param;
5457 memset(&msg_param, 0, sizeof(MMMessageParamType));
5459 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5460 LOGW("not found AUDIO codec, posting error code to application.");
5462 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5463 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5464 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5465 LOGW("not found VIDEO codec, posting error code to application.");
5467 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5468 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5471 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5473 MMPLAYER_FREEIF(msg_param.data);
5475 return MM_ERROR_NONE;
5477 // no any supported codec case
5478 LOGW("not found any codec, posting error code to application.");
5480 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5481 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5482 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5484 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5485 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5488 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5490 MMPLAYER_FREEIF(msg_param.data);
5496 return MM_ERROR_NONE;
5500 __mmplayer_check_pipeline(mmplayer_t *player)
5502 GstState element_state = GST_STATE_VOID_PENDING;
5503 GstState element_pending_state = GST_STATE_VOID_PENDING;
5505 int ret = MM_ERROR_NONE;
5507 if (!player->gapless.reconfigure)
5510 LOGW("pipeline is under construction.");
5512 MMPLAYER_PLAYBACK_LOCK(player);
5513 MMPLAYER_PLAYBACK_UNLOCK(player);
5515 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5517 /* wait for state transition */
5518 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5519 if (ret == GST_STATE_CHANGE_FAILURE)
5520 LOGE("failed to change pipeline state within %d sec", timeout);
5523 /* NOTE : it should be able to call 'stop' anytime*/
5525 _mmplayer_stop(MMHandleType hplayer)
5527 mmplayer_t *player = (mmplayer_t *)hplayer;
5528 int ret = MM_ERROR_NONE;
5532 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5534 /* check current state */
5535 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5537 /* check pipline building state */
5538 __mmplayer_check_pipeline(player);
5539 __mmplayer_reset_gapless_state(player);
5541 /* NOTE : application should not wait for EOS after calling STOP */
5542 _mmplayer_cancel_eos_timer(player);
5545 player->seek_state = MMPLAYER_SEEK_NONE;
5548 ret = _mmplayer_gst_stop(player);
5550 if (ret != MM_ERROR_NONE)
5551 LOGE("failed to stop player.");
5559 _mmplayer_pause(MMHandleType hplayer)
5561 mmplayer_t *player = (mmplayer_t *)hplayer;
5562 gint64 pos_nsec = 0;
5563 gboolean async = FALSE;
5564 gint ret = MM_ERROR_NONE;
5568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5570 /* check current state */
5571 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5573 /* check pipline building state */
5574 __mmplayer_check_pipeline(player);
5576 switch (MMPLAYER_CURRENT_STATE(player)) {
5577 case MM_PLAYER_STATE_READY:
5579 /* check prepare async or not.
5580 * In the case of streaming playback, it's recommned to avoid blocking wait.
5582 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5583 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5585 /* Changing back sync of rtspsrc to async */
5586 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5587 LOGD("async prepare working mode for rtsp");
5593 case MM_PLAYER_STATE_PLAYING:
5595 /* NOTE : store current point to overcome some bad operation
5596 *(returning zero when getting current position in paused state) of some
5599 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5600 LOGW("getting current position failed in paused");
5602 player->last_position = pos_nsec;
5604 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5605 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5606 This causes problem is position calculation during normal pause resume scenarios also.
5607 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5608 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5609 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5610 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5616 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5617 LOGD("doing async pause in case of ms buff src");
5621 /* pause pipeline */
5622 ret = _mmplayer_gst_pause(player, async);
5624 if (ret != MM_ERROR_NONE)
5625 LOGE("failed to pause player. ret : 0x%x", ret);
5627 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5628 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5629 LOGE("failed to update display_rotation");
5637 /* in case of streaming, pause could take long time.*/
5639 _mmplayer_abort_pause(MMHandleType hplayer)
5641 mmplayer_t *player = (mmplayer_t *)hplayer;
5642 int ret = MM_ERROR_NONE;
5646 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5648 player->pipeline->mainbin,
5649 MM_ERROR_PLAYER_NOT_INITIALIZED);
5651 LOGD("set the pipeline state to READY");
5653 /* set state to READY */
5654 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5655 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5656 if (ret != MM_ERROR_NONE) {
5657 LOGE("fail to change state to READY");
5658 return MM_ERROR_PLAYER_INTERNAL;
5661 LOGD("succeeded in changing state to READY");
5666 _mmplayer_resume(MMHandleType hplayer)
5668 mmplayer_t *player = (mmplayer_t *)hplayer;
5669 int ret = MM_ERROR_NONE;
5670 gboolean async = FALSE;
5674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5676 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5677 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5678 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5682 /* Changing back sync mode rtspsrc to async */
5683 LOGD("async resume for rtsp case");
5687 /* check current state */
5688 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5690 ret = _mmplayer_gst_resume(player, async);
5691 if (ret != MM_ERROR_NONE)
5692 LOGE("failed to resume player.");
5694 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5695 LOGD("force resume even during buffering");
5696 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5705 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5707 mmplayer_t *player = (mmplayer_t *)hplayer;
5708 gint64 pos_nsec = 0;
5709 int ret = MM_ERROR_NONE;
5711 signed long long start = 0, stop = 0;
5712 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5718 /* The sound of video is not supported under 0.0 and over 2.0. */
5719 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5720 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5723 _mmplayer_set_mute(hplayer, mute);
5725 if (player->playback_rate == rate)
5726 return MM_ERROR_NONE;
5728 /* If the position is reached at start potion during fast backward, EOS is posted.
5729 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5731 player->playback_rate = rate;
5733 current_state = MMPLAYER_CURRENT_STATE(player);
5735 if (current_state != MM_PLAYER_STATE_PAUSED)
5736 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5738 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5740 if ((current_state == MM_PLAYER_STATE_PAUSED)
5741 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5742 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5743 pos_nsec = player->last_position;
5748 stop = GST_CLOCK_TIME_NONE;
5750 start = GST_CLOCK_TIME_NONE;
5754 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5755 player->playback_rate,
5757 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5758 GST_SEEK_TYPE_SET, start,
5759 GST_SEEK_TYPE_SET, stop)) {
5760 LOGE("failed to set speed playback");
5761 return MM_ERROR_PLAYER_SEEK;
5764 LOGD("succeeded to set speed playback as %0.1f", rate);
5768 return MM_ERROR_NONE;;
5772 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5774 mmplayer_t *player = (mmplayer_t *)hplayer;
5775 int ret = MM_ERROR_NONE;
5779 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5781 /* check pipline building state */
5782 __mmplayer_check_pipeline(player);
5784 ret = _mmplayer_gst_set_position(player, position, FALSE);
5792 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5794 mmplayer_t *player = (mmplayer_t *)hplayer;
5795 int ret = MM_ERROR_NONE;
5797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5798 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5800 if (g_strrstr(player->type, "video/mpegts"))
5801 __mmplayer_update_duration_value(player);
5803 *duration = player->duration;
5808 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5810 mmplayer_t *player = (mmplayer_t *)hplayer;
5811 int ret = MM_ERROR_NONE;
5813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5815 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5821 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5823 mmplayer_t *player = (mmplayer_t *)hplayer;
5824 int ret = MM_ERROR_NONE;
5828 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5830 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5838 __mmplayer_is_midi_type(gchar *str_caps)
5840 if ((g_strrstr(str_caps, "audio/midi")) ||
5841 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5842 (g_strrstr(str_caps, "application/x-smaf")) ||
5843 (g_strrstr(str_caps, "audio/x-imelody")) ||
5844 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5845 (g_strrstr(str_caps, "audio/xmf")) ||
5846 (g_strrstr(str_caps, "audio/mxmf"))) {
5855 __mmplayer_is_only_mp3_type(gchar *str_caps)
5857 if (g_strrstr(str_caps, "application/x-id3") ||
5858 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5864 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5866 GstStructure *caps_structure = NULL;
5867 gint samplerate = 0;
5871 MMPLAYER_RETURN_IF_FAIL(player && caps);
5873 caps_structure = gst_caps_get_structure(caps, 0);
5875 /* set stream information */
5876 gst_structure_get_int(caps_structure, "rate", &samplerate);
5877 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5879 gst_structure_get_int(caps_structure, "channels", &channels);
5880 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5882 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5886 __mmplayer_update_content_type_info(mmplayer_t *player)
5889 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5891 if (__mmplayer_is_midi_type(player->type)) {
5892 player->bypass_audio_effect = TRUE;
5896 if (!player->streamer) {
5897 LOGD("no need to check streaming type");
5901 if (g_strrstr(player->type, "application/x-hls")) {
5902 /* If it can't know exact type when it parses uri because of redirection case,
5903 * it will be fixed by typefinder or when doing autoplugging.
5905 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5906 player->streamer->is_adaptive_streaming = TRUE;
5907 } else if (g_strrstr(player->type, "application/dash+xml")) {
5908 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5909 player->streamer->is_adaptive_streaming = TRUE;
5912 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5913 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5914 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5916 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5917 if (player->streamer->is_adaptive_streaming)
5918 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5920 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5924 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5929 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5930 GstCaps *caps, gpointer data)
5932 mmplayer_t *player = (mmplayer_t *)data;
5937 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5939 /* store type string */
5940 MMPLAYER_FREEIF(player->type);
5941 player->type = gst_caps_to_string(caps);
5943 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5944 player, player->type, probability, gst_caps_get_size(caps));
5946 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5947 (g_strrstr(player->type, "audio/x-raw-int"))) {
5948 LOGE("not support media format");
5950 if (player->msg_posted == FALSE) {
5951 MMMessageParamType msg_param;
5952 memset(&msg_param, 0, sizeof(MMMessageParamType));
5954 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5955 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5957 /* don't post more if one was sent already */
5958 player->msg_posted = TRUE;
5963 __mmplayer_update_content_type_info(player);
5965 pad = gst_element_get_static_pad(tf, "src");
5967 LOGE("fail to get typefind src pad.");
5971 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5972 gboolean async = FALSE;
5973 LOGE("failed to autoplug %s", player->type);
5975 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5977 if (async && player->msg_posted == FALSE)
5978 __mmplayer_handle_missed_plugin(player);
5982 gst_object_unref(GST_OBJECT(pad));
5990 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5992 GstElement *decodebin = NULL;
5996 /* create decodebin */
5997 decodebin = gst_element_factory_make("decodebin", NULL);
6000 LOGE("fail to create decodebin");
6004 /* raw pad handling signal */
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6006 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6008 /* no-more-pad pad handling signal */
6009 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6010 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6012 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6013 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6015 /* This signal is emitted when a pad for which there is no further possible
6016 decoding is added to the decodebin.*/
6017 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6018 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6020 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6021 before looking for any elements that can handle that stream.*/
6022 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6023 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6025 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6026 before looking for any elements that can handle that stream.*/
6027 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6028 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6030 /* This signal is emitted once decodebin has finished decoding all the data.*/
6031 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6032 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6034 /* This signal is emitted when a element is added to the bin.*/
6035 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6036 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6043 __mmplayer_gst_make_queue2(mmplayer_t *player)
6045 GstElement *queue2 = NULL;
6046 gint64 dur_bytes = 0L;
6047 mmplayer_gst_element_t *mainbin = NULL;
6048 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6051 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6053 mainbin = player->pipeline->mainbin;
6055 queue2 = gst_element_factory_make("queue2", "queue2");
6057 LOGE("failed to create buffering queue element");
6061 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6062 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6064 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6066 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6067 * skip the pull mode(file or ring buffering) setting. */
6068 if (dur_bytes > 0) {
6069 if (!g_strrstr(player->type, "video/mpegts")) {
6070 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6071 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6077 _mm_player_streaming_set_queue2(player->streamer,
6081 (guint64)dur_bytes); /* no meaning at the moment */
6087 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6089 mmplayer_gst_element_t *mainbin = NULL;
6090 GstElement *decodebin = NULL;
6091 GstElement *queue2 = NULL;
6092 GstPad *sinkpad = NULL;
6093 GstPad *qsrcpad = NULL;
6096 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6098 mainbin = player->pipeline->mainbin;
6100 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6102 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6103 LOGW("need to check: muxed buffer is not null");
6106 queue2 = __mmplayer_gst_make_queue2(player);
6108 LOGE("failed to make queue2");
6112 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6113 LOGE("failed to add buffering queue");
6117 sinkpad = gst_element_get_static_pad(queue2, "sink");
6118 qsrcpad = gst_element_get_static_pad(queue2, "src");
6120 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6121 LOGE("failed to link [%s:%s]-[%s:%s]",
6122 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6126 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6127 LOGE("failed to sync queue2 state with parent");
6131 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6132 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6136 gst_object_unref(GST_OBJECT(sinkpad));
6140 /* create decodebin */
6141 decodebin = _mmplayer_gst_make_decodebin(player);
6143 LOGE("failed to make decodebin");
6147 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6148 LOGE("failed to add decodebin");
6152 /* to force caps on the decodebin element and avoid reparsing stuff by
6153 * typefind. It also avoids a deadlock in the way typefind activates pads in
6154 * the state change */
6155 g_object_set(decodebin, "sink-caps", caps, NULL);
6157 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6159 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6160 LOGE("failed to link [%s:%s]-[%s:%s]",
6161 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6165 gst_object_unref(GST_OBJECT(sinkpad));
6167 gst_object_unref(GST_OBJECT(qsrcpad));
6170 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6171 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6173 /* set decodebin property about buffer in streaming playback. *
6174 * in case of HLS/DASH, it does not need to have big buffer *
6175 * because it is kind of adaptive streaming. */
6176 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6177 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6178 gint high_percent = 0;
6180 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6181 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6183 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6185 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6187 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6188 "high-percent", high_percent,
6189 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6190 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6191 "max-size-buffers", 0, NULL); // disable or automatic
6194 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6195 LOGE("failed to sync decodebin state with parent");
6206 gst_object_unref(GST_OBJECT(sinkpad));
6209 gst_object_unref(GST_OBJECT(qsrcpad));
6212 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6213 * You need to explicitly set elements to the NULL state before
6214 * dropping the final reference, to allow them to clean up.
6216 gst_element_set_state(queue2, GST_STATE_NULL);
6218 /* And, it still has a parent "player".
6219 * You need to let the parent manage the object instead of unreffing the object directly.
6221 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6222 gst_object_unref(queue2);
6227 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6228 * You need to explicitly set elements to the NULL state before
6229 * dropping the final reference, to allow them to clean up.
6231 gst_element_set_state(decodebin, GST_STATE_NULL);
6233 /* And, it still has a parent "player".
6234 * You need to let the parent manage the object instead of unreffing the object directly.
6237 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6238 gst_object_unref(decodebin);
6246 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6250 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6251 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6253 LOGD("class : %s, mime : %s", factory_class, mime);
6255 /* add missing plugin */
6256 /* NOTE : msl should check missing plugin for image mime type.
6257 * Some motion jpeg clips can have playable audio track.
6258 * So, msl have to play audio after displaying popup written video format not supported.
6260 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6261 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6262 LOGD("not found demuxer");
6263 player->not_found_demuxer = TRUE;
6264 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6270 if (!g_strrstr(factory_class, "Demuxer")) {
6271 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6272 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6273 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6275 /* check that clip have multi tracks or not */
6276 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6277 LOGD("video plugin is already linked");
6279 LOGW("add VIDEO to missing plugin");
6280 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6281 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6283 } else if (g_str_has_prefix(mime, "audio")) {
6284 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6285 LOGD("audio plugin is already linked");
6287 LOGW("add AUDIO to missing plugin");
6288 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6289 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6297 return MM_ERROR_NONE;
6301 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6303 mmplayer_t *player = (mmplayer_t *)data;
6307 MMPLAYER_RETURN_IF_FAIL(player);
6309 /* remove fakesink. */
6310 if (!_mmplayer_gst_remove_fakesink(player,
6311 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6312 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6313 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6314 * source element are not same. To overcome this situation, this function will called
6315 * several places and several times. Therefore, this is not an error case.
6320 LOGD("[handle: %p] pipeline has completely constructed", player);
6322 if ((player->ini.async_start) &&
6323 (player->msg_posted == FALSE) &&
6324 (player->cmd >= MMPLAYER_COMMAND_START))
6325 __mmplayer_handle_missed_plugin(player);
6327 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6331 __mmplayer_check_profile(void)
6334 static int profile_tv = -1;
6336 if (__builtin_expect(profile_tv != -1, 1))
6339 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6340 switch (*profileName) {
6355 __mmplayer_get_next_uri(mmplayer_t *player)
6357 mmplayer_parse_profile_t profile;
6359 guint num_of_list = 0;
6362 num_of_list = g_list_length(player->uri_info.uri_list);
6363 uri_idx = player->uri_info.uri_idx;
6365 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6366 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6367 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6369 LOGW("next uri does not exist");
6373 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6374 LOGE("failed to parse profile");
6378 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6379 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6380 LOGW("uri type is not supported(%d)", profile.uri_type);
6384 LOGD("success to find next uri %d", uri_idx);
6388 if (uri_idx == num_of_list) {
6389 LOGE("failed to find next uri");
6393 player->uri_info.uri_idx = uri_idx;
6394 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6396 if (mm_attrs_commit_all(player->attrs)) {
6397 LOGE("failed to commit");
6401 SECURE_LOGD("next playback uri: %s", uri);
6406 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6408 #define REPEAT_COUNT_INFINITE -1
6409 #define REPEAT_COUNT_MIN 2
6410 #define ORIGINAL_URI_ONLY 1
6412 MMHandleType attrs = 0;
6416 guint num_of_uri = 0;
6417 int profile_tv = -1;
6421 LOGD("checking for gapless play option");
6423 if (player->build_audio_offload) {
6424 LOGE("offload path is not supportable.");
6428 if (player->pipeline->textbin) {
6429 LOGE("subtitle path is enabled. gapless play is not supported.");
6433 attrs = MMPLAYER_GET_ATTRS(player);
6435 LOGE("fail to get attributes.");
6439 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6441 /* gapless playback is not supported in case of video at TV profile. */
6442 profile_tv = __mmplayer_check_profile();
6443 if (profile_tv && video) {
6444 LOGW("not support video gapless playback");
6448 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6449 LOGE("failed to get play count");
6451 if (mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless) != MM_ERROR_NONE)
6452 LOGE("failed to get gapless mode");
6454 /* check repeat count in case of audio */
6456 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6457 LOGW("gapless is disabled");
6461 num_of_uri = g_list_length(player->uri_info.uri_list);
6463 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6465 if (num_of_uri == ORIGINAL_URI_ONLY) {
6466 /* audio looping path */
6467 if (count >= REPEAT_COUNT_MIN) {
6468 /* decrease play count */
6469 /* we succeeded to rewind. update play count and then wait for next EOS */
6471 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6472 /* commit attribute */
6473 if (mm_attrs_commit_all(attrs))
6474 LOGE("failed to commit attribute");
6476 } else if (count != REPEAT_COUNT_INFINITE) {
6477 LOGD("there is no next uri and no repeat");
6480 LOGD("looping cnt %d", count);
6482 /* gapless playback path */
6483 if (!__mmplayer_get_next_uri(player)) {
6484 LOGE("failed to get next uri");
6491 LOGE("unable to play gapless path. EOS will be posted soon");
6496 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6498 mmplayer_selector_t *selector = &player->selector[type];
6499 mmplayer_gst_element_t *sinkbin = NULL;
6500 main_element_id_e selectorId = MMPLAYER_M_NUM;
6501 main_element_id_e sinkId = MMPLAYER_M_NUM;
6502 GstPad *srcpad = NULL;
6503 GstPad *sinkpad = NULL;
6504 gboolean send_notice = FALSE;
6507 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6509 LOGD("type %d", type);
6512 case MM_PLAYER_TRACK_TYPE_AUDIO:
6513 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6514 sinkId = MMPLAYER_A_BIN;
6515 sinkbin = player->pipeline->audiobin;
6517 case MM_PLAYER_TRACK_TYPE_VIDEO:
6518 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6519 sinkId = MMPLAYER_V_BIN;
6520 sinkbin = player->pipeline->videobin;
6523 case MM_PLAYER_TRACK_TYPE_TEXT:
6524 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6525 sinkId = MMPLAYER_T_BIN;
6526 sinkbin = player->pipeline->textbin;
6529 LOGE("requested type is not supportable");
6534 if (player->pipeline->mainbin[selectorId].gst) {
6537 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6539 if (selector->event_probe_id != 0)
6540 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6541 selector->event_probe_id = 0;
6543 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6544 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6546 if (srcpad && sinkpad) {
6547 /* after getting drained signal there is no data flows, so no need to do pad_block */
6548 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6549 gst_pad_unlink(srcpad, sinkpad);
6551 /* send custom event to sink pad to handle it at video sink */
6553 LOGD("send custom event to sinkpad");
6554 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6555 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6556 gst_pad_send_event(sinkpad, event);
6560 gst_object_unref(sinkpad);
6563 gst_object_unref(srcpad);
6566 LOGD("selector release");
6568 /* release and unref requests pad from the selector */
6569 for (n = 0; n < selector->channels->len; n++) {
6570 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6571 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6573 g_ptr_array_set_size(selector->channels, 0);
6575 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6576 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6578 player->pipeline->mainbin[selectorId].gst = NULL;
6586 __mmplayer_deactivate_old_path(mmplayer_t *player)
6589 MMPLAYER_RETURN_IF_FAIL(player);
6591 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6592 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6593 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6594 LOGE("deactivate selector error");
6598 _mmplayer_track_destroy(player);
6599 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6601 if (player->streamer) {
6602 _mm_player_streaming_initialize(player->streamer, FALSE);
6603 _mm_player_streaming_destroy(player->streamer);
6604 player->streamer = NULL;
6607 MMPLAYER_PLAYBACK_LOCK(player);
6608 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6615 if (!player->msg_posted) {
6616 MMMessageParamType msg = {0,};
6619 msg.code = MM_ERROR_PLAYER_INTERNAL;
6620 LOGE("gapless_uri_play> deactivate error");
6622 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6623 player->msg_posted = TRUE;
6629 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6631 int result = MM_ERROR_NONE;
6632 mmplayer_t *player = (mmplayer_t *)hplayer;
6635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6637 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6638 if (mm_attrs_commit_all(player->attrs)) {
6639 LOGE("failed to commit the original uri.");
6640 result = MM_ERROR_PLAYER_INTERNAL;
6642 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6643 LOGE("failed to add the original uri in the uri list.");
6651 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6653 mmplayer_t *player = (mmplayer_t *)hplayer;
6654 guint num_of_list = 0;
6658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6659 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6661 if (player->pipeline && player->pipeline->textbin) {
6662 LOGE("subtitle path is enabled.");
6663 return MM_ERROR_PLAYER_INVALID_STATE;
6666 num_of_list = g_list_length(player->uri_info.uri_list);
6668 if (is_first_path) {
6669 if (num_of_list == 0) {
6670 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6671 SECURE_LOGD("add original path : %s", uri);
6673 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6674 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6676 SECURE_LOGD("change original path : %s", uri);
6679 MMHandleType attrs = 0;
6680 attrs = MMPLAYER_GET_ATTRS(player);
6682 if (num_of_list == 0) {
6683 char *original_uri = NULL;
6686 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6688 if (!original_uri) {
6689 LOGE("there is no original uri.");
6690 return MM_ERROR_PLAYER_INVALID_STATE;
6693 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6694 player->uri_info.uri_idx = 0;
6696 SECURE_LOGD("add original path at first : %s", original_uri);
6700 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6701 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6705 return MM_ERROR_NONE;
6709 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6711 mmplayer_t *player = (mmplayer_t *)hplayer;
6712 char *next_uri = NULL;
6713 guint num_of_list = 0;
6716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6718 num_of_list = g_list_length(player->uri_info.uri_list);
6720 if (num_of_list > 0) {
6721 gint uri_idx = player->uri_info.uri_idx;
6723 if (uri_idx < num_of_list-1)
6728 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6729 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6731 *uri = g_strdup(next_uri);
6735 return MM_ERROR_NONE;
6739 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6740 GstCaps *caps, gpointer data)
6742 mmplayer_t *player = (mmplayer_t *)data;
6743 const gchar *klass = NULL;
6744 const gchar *mime = NULL;
6745 gchar *caps_str = NULL;
6747 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6748 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6749 caps_str = gst_caps_to_string(caps);
6751 LOGW("unknown type of caps : %s from %s",
6752 caps_str, GST_ELEMENT_NAME(elem));
6754 MMPLAYER_FREEIF(caps_str);
6756 /* There is no available codec. */
6757 __mmplayer_check_not_supported_codec(player, klass, mime);
6761 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6762 GstCaps *caps, gpointer data)
6764 mmplayer_t *player = (mmplayer_t *)data;
6765 const char *mime = NULL;
6766 gboolean ret = TRUE;
6768 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6769 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6771 if (g_str_has_prefix(mime, "audio")) {
6772 GstStructure *caps_structure = NULL;
6773 gint samplerate = 0;
6775 gchar *caps_str = NULL;
6777 caps_structure = gst_caps_get_structure(caps, 0);
6778 gst_structure_get_int(caps_structure, "rate", &samplerate);
6779 gst_structure_get_int(caps_structure, "channels", &channels);
6781 if ((channels > 0 && samplerate == 0)) {
6782 LOGD("exclude audio...");
6786 caps_str = gst_caps_to_string(caps);
6787 /* set it directly because not sent by TAG */
6788 if (g_strrstr(caps_str, "mobile-xmf"))
6789 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6790 MMPLAYER_FREEIF(caps_str);
6791 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6792 MMMessageParamType msg_param;
6793 memset(&msg_param, 0, sizeof(MMMessageParamType));
6794 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6795 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6796 LOGD("video file is not supported on this device");
6798 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6799 LOGD("already video linked");
6802 LOGD("found new stream");
6809 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6811 gboolean ret = TRUE;
6812 GDBusConnection *conn = NULL;
6814 GVariant *result = NULL;
6815 const gchar *dbus_device_type = NULL;
6816 const gchar *dbus_ret = NULL;
6819 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6821 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6827 result = g_dbus_connection_call_sync(conn,
6828 "org.pulseaudio.Server",
6829 "/org/pulseaudio/StreamManager",
6830 "org.pulseaudio.StreamManager",
6831 "GetCurrentMediaRoutingPath",
6832 g_variant_new("(s)", "out"),
6833 G_VARIANT_TYPE("(ss)"),
6834 G_DBUS_CALL_FLAGS_NONE,
6838 if (!result || err) {
6839 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6845 /* device type is listed in stream-map.json at mmfw-sysconf */
6846 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6848 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6849 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6854 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6855 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6856 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6857 LOGD("audio offload is supportable");
6863 LOGD("audio offload is not supportable");
6867 g_variant_unref(result);
6868 g_object_unref(conn);
6873 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6875 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6876 gint64 position = 0;
6878 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6879 player->pipeline && player->pipeline->mainbin);
6881 MMPLAYER_CMD_LOCK(player);
6882 current_state = MMPLAYER_CURRENT_STATE(player);
6884 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6885 LOGW("getting current position failed in paused");
6887 _mmplayer_unrealize((MMHandleType)player);
6888 _mmplayer_realize((MMHandleType)player);
6890 _mmplayer_set_position((MMHandleType)player, position);
6892 /* async not to be blocked in streaming case */
6893 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6894 if (mm_attrs_commit_all(player->attrs))
6895 LOGE("failed to commit");
6897 _mmplayer_pause((MMHandleType)player);
6899 if (current_state == MM_PLAYER_STATE_PLAYING)
6900 _mmplayer_start((MMHandleType)player);
6901 MMPLAYER_CMD_UNLOCK(player);
6903 LOGD("rebuilding audio pipeline is completed.");
6906 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6908 mmplayer_t *player = (mmplayer_t *)user_data;
6909 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6910 gboolean is_supportable = FALSE;
6912 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6913 LOGW("failed to get device type");
6915 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6917 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6918 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6919 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6920 LOGD("ignore this dev connected info");
6924 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6925 if (player->build_audio_offload == is_supportable) {
6926 LOGD("keep current pipeline without re-building");
6930 /* rebuild pipeline */
6931 LOGD("re-build pipeline - offload: %d", is_supportable);
6932 player->build_audio_offload = FALSE;
6933 __mmplayer_rebuild_audio_pipeline(player);
6939 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6941 unsigned int id = 0;
6943 if (player->audio_device_cb_id != 0) {
6944 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6948 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6949 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6950 LOGD("added device connected cb (%u)", id);
6951 player->audio_device_cb_id = id;
6953 LOGW("failed to add device connected cb");
6961 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6963 gboolean ret = FALSE;
6964 GstElementFactory *factory = NULL;
6967 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6969 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6970 if (!__mmplayer_is_only_mp3_type(player->type))
6973 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6974 LOGD("there is no audio offload sink");
6978 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6979 LOGW("there is no audio device type to support offload");
6983 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6985 LOGW("there is no installed audio offload sink element");
6988 gst_object_unref(factory);
6990 if (__mmplayer_acquire_hw_resource(player,
6991 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6992 LOGE("failed to acquire audio offload decoder resource");
6996 if (!__mmplayer_add_audio_device_connected_cb(player))
6999 if (!__mmplayer_is_audio_offload_device_type(player))
7002 LOGD("audio offload can be built");
7007 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7013 static GstAutoplugSelectResult
7014 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7016 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7018 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7019 int audio_offload = 0;
7021 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7022 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7024 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7025 LOGD("expose audio path to build offload output path");
7026 player->build_audio_offload = TRUE;
7027 /* update codec info */
7028 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7029 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7030 player->audiodec_linked = 1;
7032 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7036 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7038 LOGD("audio codec type: %d", codec_type);
7039 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7040 /* sw codec will be skipped */
7041 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7042 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7043 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7044 ret = GST_AUTOPLUG_SELECT_SKIP;
7048 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7049 /* hw codec will be skipped */
7050 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7051 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7052 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7053 ret = GST_AUTOPLUG_SELECT_SKIP;
7058 /* set stream information */
7059 if (!player->audiodec_linked)
7060 __mmplayer_set_audio_attrs(player, caps);
7062 /* update codec info */
7063 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7064 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7065 player->audiodec_linked = 1;
7067 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7069 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7071 LOGD("video codec type: %d", codec_type);
7072 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7073 /* sw codec is skipped */
7074 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7075 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7076 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7077 ret = GST_AUTOPLUG_SELECT_SKIP;
7081 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7082 /* hw codec is skipped */
7083 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7084 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7085 ret = GST_AUTOPLUG_SELECT_SKIP;
7090 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7091 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7093 /* mark video decoder for acquire */
7094 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7095 LOGW("video decoder resource is already acquired, skip it.");
7096 ret = GST_AUTOPLUG_SELECT_SKIP;
7100 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7101 LOGE("failed to acquire video decoder resource");
7102 ret = GST_AUTOPLUG_SELECT_SKIP;
7105 player->interrupted_by_resource = FALSE;
7108 /* update codec info */
7109 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7110 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7111 player->videodec_linked = 1;
7119 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7120 GstCaps *caps, GstElementFactory *factory, gpointer data)
7122 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7123 mmplayer_t *player = (mmplayer_t *)data;
7125 gchar *factory_name = NULL;
7126 gchar *caps_str = NULL;
7127 const gchar *klass = NULL;
7130 factory_name = GST_OBJECT_NAME(factory);
7131 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7132 caps_str = gst_caps_to_string(caps);
7134 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7136 /* store type string */
7137 if (player->type == NULL) {
7138 player->type = gst_caps_to_string(caps);
7139 __mmplayer_update_content_type_info(player);
7142 /* filtering exclude keyword */
7143 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7144 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7145 LOGW("skipping [%s] by exculde keyword [%s]",
7146 factory_name, player->ini.exclude_element_keyword[idx]);
7148 result = GST_AUTOPLUG_SELECT_SKIP;
7153 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7154 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7155 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7156 factory_name, player->ini.unsupported_codec_keyword[idx]);
7157 result = GST_AUTOPLUG_SELECT_SKIP;
7162 /* exclude webm format */
7163 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7164 * because webm format is not supportable.
7165 * If webm is disabled in "autoplug-continue", there is no state change
7166 * failure or error because the decodebin will expose the pad directly.
7167 * It make MSL invoke _prepare_async_callback.
7168 * So, we need to disable webm format in "autoplug-select" */
7169 if (caps_str && strstr(caps_str, "webm")) {
7170 LOGW("webm is not supported");
7171 result = GST_AUTOPLUG_SELECT_SKIP;
7175 /* check factory class for filtering */
7176 /* NOTE : msl don't need to use image plugins.
7177 * So, those plugins should be skipped for error handling.
7179 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7180 LOGD("skipping [%s] by not required", factory_name);
7181 result = GST_AUTOPLUG_SELECT_SKIP;
7185 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7186 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7187 // TO CHECK : subtitle if needed, add subparse exception.
7188 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7189 result = GST_AUTOPLUG_SELECT_SKIP;
7193 if (g_strrstr(factory_name, "mpegpsdemux")) {
7194 LOGD("skipping PS container - not support");
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7199 if (g_strrstr(factory_name, "mssdemux"))
7200 player->smooth_streaming = TRUE;
7202 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7203 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7206 GstStructure *str = NULL;
7207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7209 /* don't make video because of not required */
7210 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7211 (!player->set_mode.video_export)) {
7212 LOGD("no need video decoding, expose pad");
7213 result = GST_AUTOPLUG_SELECT_EXPOSE;
7217 /* get w/h for omx state-tune */
7218 /* FIXME: deprecated? */
7219 str = gst_caps_get_structure(caps, 0);
7220 gst_structure_get_int(str, "width", &width);
7223 if (player->v_stream_caps) {
7224 gst_caps_unref(player->v_stream_caps);
7225 player->v_stream_caps = NULL;
7228 player->v_stream_caps = gst_caps_copy(caps);
7229 LOGD("take caps for video state tune");
7230 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7234 if (g_strrstr(klass, "Codec/Decoder")) {
7235 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7236 if (result != GST_AUTOPLUG_SELECT_TRY) {
7237 LOGW("skip add decoder");
7243 MMPLAYER_FREEIF(caps_str);
7249 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7252 //mmplayer_t *player = (mmplayer_t *)data;
7253 GstCaps *caps = NULL;
7255 LOGD("[Decodebin2] pad-removed signal");
7257 caps = gst_pad_query_caps(new_pad, NULL);
7259 LOGW("query caps is NULL");
7263 gchar *caps_str = NULL;
7264 caps_str = gst_caps_to_string(caps);
7266 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7268 MMPLAYER_FREEIF(caps_str);
7269 gst_caps_unref(caps);
7273 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7275 mmplayer_t *player = (mmplayer_t *)data;
7276 GstIterator *iter = NULL;
7277 GValue item = { 0, };
7279 gboolean done = FALSE;
7280 gboolean is_all_drained = TRUE;
7283 MMPLAYER_RETURN_IF_FAIL(player);
7285 LOGD("__mmplayer_gst_decode_drained");
7287 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7288 LOGW("Fail to get cmd lock");
7292 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7293 !__mmplayer_verify_gapless_play_path(player)) {
7294 LOGD("decoding is finished.");
7295 __mmplayer_reset_gapless_state(player);
7296 MMPLAYER_CMD_UNLOCK(player);
7300 player->gapless.reconfigure = TRUE;
7302 /* check decodebin src pads whether they received EOS or not */
7303 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7306 switch (gst_iterator_next(iter, &item)) {
7307 case GST_ITERATOR_OK:
7308 pad = g_value_get_object(&item);
7309 if (pad && !GST_PAD_IS_EOS(pad)) {
7310 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7311 is_all_drained = FALSE;
7314 g_value_reset(&item);
7316 case GST_ITERATOR_RESYNC:
7317 gst_iterator_resync(iter);
7319 case GST_ITERATOR_ERROR:
7320 case GST_ITERATOR_DONE:
7325 g_value_unset(&item);
7326 gst_iterator_free(iter);
7328 if (!is_all_drained) {
7329 LOGD("Wait util the all pads get EOS.");
7330 MMPLAYER_CMD_UNLOCK(player);
7335 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7336 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7338 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7339 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7340 __mmplayer_deactivate_old_path(player);
7341 MMPLAYER_CMD_UNLOCK(player);
7347 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7349 mmplayer_t *player = (mmplayer_t *)data;
7350 const gchar *klass = NULL;
7351 gchar *factory_name = NULL;
7353 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7354 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7356 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7358 if (__mmplayer_add_dump_buffer_probe(player, element))
7359 LOGD("add buffer probe");
7361 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7362 gchar *selected = NULL;
7363 selected = g_strdup(GST_ELEMENT_NAME(element));
7364 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7367 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7368 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7369 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7371 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7372 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7374 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7375 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7376 "max-video-width", player->adaptive_info.limit.width,
7377 "max-video-height", player->adaptive_info.limit.height, NULL);
7379 } else if (g_strrstr(klass, "Demuxer")) {
7381 LOGD("plugged element is demuxer. take it");
7383 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7384 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7387 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7388 int surface_type = 0;
7390 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7393 // to support trust-zone only
7394 if (g_strrstr(factory_name, "asfdemux")) {
7395 LOGD("set file-location %s", player->profile.uri);
7396 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7397 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7398 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7399 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7400 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7401 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7402 (__mmplayer_is_only_mp3_type(player->type))) {
7403 LOGD("[mpegaudioparse] set streaming pull mode.");
7404 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7406 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7407 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7410 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7411 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7412 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7414 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7415 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7417 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7418 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7419 (MMPLAYER_IS_DASH_STREAMING(player))) {
7420 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7421 _mm_player_streaming_set_multiqueue(player->streamer, element);
7422 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7431 __mmplayer_release_misc(mmplayer_t *player)
7434 bool cur_mode = player->set_mode.rich_audio;
7437 MMPLAYER_RETURN_IF_FAIL(player);
7439 player->video_decoded_cb = NULL;
7440 player->video_decoded_cb_user_param = NULL;
7441 player->video_stream_prerolled = false;
7443 player->audio_decoded_cb = NULL;
7444 player->audio_decoded_cb_user_param = NULL;
7445 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7447 player->audio_stream_changed_cb = NULL;
7448 player->audio_stream_changed_cb_user_param = NULL;
7450 player->sent_bos = FALSE;
7451 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7453 player->seek_state = MMPLAYER_SEEK_NONE;
7455 player->total_bitrate = 0;
7456 player->total_maximum_bitrate = 0;
7458 player->not_found_demuxer = 0;
7460 player->last_position = 0;
7461 player->duration = 0;
7462 player->http_content_size = 0;
7463 player->not_supported_codec = MISSING_PLUGIN_NONE;
7464 player->can_support_codec = FOUND_PLUGIN_NONE;
7465 player->pending_seek.is_pending = false;
7466 player->pending_seek.pos = 0;
7467 player->msg_posted = FALSE;
7468 player->has_many_types = FALSE;
7469 player->is_subtitle_force_drop = FALSE;
7470 player->play_subtitle = FALSE;
7471 player->adjust_subtitle_pos = 0;
7472 player->has_closed_caption = FALSE;
7473 player->set_mode.video_export = false;
7474 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7475 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7477 player->set_mode.rich_audio = cur_mode;
7479 if (player->audio_device_cb_id > 0 &&
7480 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7481 LOGW("failed to remove audio device_connected_callback");
7482 player->audio_device_cb_id = 0;
7484 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7485 player->bitrate[i] = 0;
7486 player->maximum_bitrate[i] = 0;
7489 /* free memory related to audio effect */
7490 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7492 if (player->adaptive_info.var_list) {
7493 g_list_free_full(player->adaptive_info.var_list, g_free);
7494 player->adaptive_info.var_list = NULL;
7497 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7498 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7499 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7501 /* Reset video360 settings to their defaults in case if the pipeline is to be
7504 player->video360_metadata.is_spherical = -1;
7505 player->is_openal_plugin_used = FALSE;
7507 player->is_content_spherical = FALSE;
7508 player->is_video360_enabled = TRUE;
7509 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7510 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7511 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7512 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7513 player->video360_zoom = 1.0f;
7514 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7515 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7517 player->sound.rg_enable = false;
7519 __mmplayer_initialize_video_roi(player);
7524 __mmplayer_release_misc_post(mmplayer_t *player)
7526 char *original_uri = NULL;
7529 /* player->pipeline is already released before. */
7531 MMPLAYER_RETURN_IF_FAIL(player);
7533 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7535 /* clean found audio decoders */
7536 if (player->audio_decoders) {
7537 GList *a_dec = player->audio_decoders;
7538 for (; a_dec; a_dec = g_list_next(a_dec)) {
7539 gchar *name = a_dec->data;
7540 MMPLAYER_FREEIF(name);
7542 g_list_free(player->audio_decoders);
7543 player->audio_decoders = NULL;
7546 /* clean the uri list except original uri */
7547 if (player->uri_info.uri_list) {
7548 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7550 if (player->attrs) {
7551 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7552 LOGD("restore original uri = %s", original_uri);
7554 if (mm_attrs_commit_all(player->attrs))
7555 LOGE("failed to commit the original uri.");
7558 GList *uri_list = player->uri_info.uri_list;
7559 for (; uri_list; uri_list = g_list_next(uri_list)) {
7560 gchar *uri = uri_list->data;
7561 MMPLAYER_FREEIF(uri);
7563 g_list_free(player->uri_info.uri_list);
7564 player->uri_info.uri_list = NULL;
7567 /* clear the audio stream buffer list */
7568 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7570 /* clear the video stream bo list */
7571 __mmplayer_video_stream_destroy_bo_list(player);
7572 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7574 if (player->profile.input_mem.buf) {
7575 free(player->profile.input_mem.buf);
7576 player->profile.input_mem.buf = NULL;
7578 player->profile.input_mem.len = 0;
7579 player->profile.input_mem.offset = 0;
7581 player->uri_info.uri_idx = 0;
7586 __mmplayer_check_subtitle(mmplayer_t *player)
7588 MMHandleType attrs = 0;
7589 char *subtitle_uri = NULL;
7593 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7595 /* get subtitle attribute */
7596 attrs = MMPLAYER_GET_ATTRS(player);
7600 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7601 if (!subtitle_uri || !strlen(subtitle_uri))
7604 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7605 player->is_external_subtitle_present = TRUE;
7613 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7615 MMPLAYER_RETURN_IF_FAIL(player);
7617 if (player->eos_timer) {
7618 LOGD("cancel eos timer");
7619 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7620 player->eos_timer = 0;
7627 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7631 MMPLAYER_RETURN_IF_FAIL(player);
7632 MMPLAYER_RETURN_IF_FAIL(sink);
7634 player->sink_elements = g_list_append(player->sink_elements, sink);
7640 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7644 MMPLAYER_RETURN_IF_FAIL(player);
7645 MMPLAYER_RETURN_IF_FAIL(sink);
7647 player->sink_elements = g_list_remove(player->sink_elements, sink);
7653 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7654 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7656 mmplayer_signal_item_t *item = NULL;
7659 MMPLAYER_RETURN_IF_FAIL(player);
7661 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7662 LOGE("invalid signal type [%d]", type);
7666 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7668 LOGE("cannot connect signal [%s]", signal);
7673 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7674 player->signals[type] = g_list_append(player->signals[type], item);
7680 /* NOTE : be careful with calling this api. please refer to below glib comment
7681 * glib comment : Note that there is a bug in GObject that makes this function much
7682 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7683 * will no longer be called, but, the signal handler is not currently disconnected.
7684 * If the instance is itself being freed at the same time than this doesn't matter,
7685 * since the signal will automatically be removed, but if instance persists,
7686 * then the signal handler will leak. You should not remove the signal yourself
7687 * because in a future versions of GObject, the handler will automatically be
7690 * It's possible to work around this problem in a way that will continue to work
7691 * with future versions of GObject by checking that the signal handler is still
7692 * connected before disconnected it:
7694 * if (g_signal_handler_is_connected(instance, id))
7695 * g_signal_handler_disconnect(instance, id);
7698 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7700 GList *sig_list = NULL;
7701 mmplayer_signal_item_t *item = NULL;
7705 MMPLAYER_RETURN_IF_FAIL(player);
7707 LOGD("release signals type : %d", type);
7709 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7710 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7711 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7712 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7713 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7714 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7718 sig_list = player->signals[type];
7720 for (; sig_list; sig_list = sig_list->next) {
7721 item = sig_list->data;
7723 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7724 if (g_signal_handler_is_connected(item->obj, item->sig))
7725 g_signal_handler_disconnect(item->obj, item->sig);
7728 MMPLAYER_FREEIF(item);
7731 g_list_free(player->signals[type]);
7732 player->signals[type] = NULL;
7740 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7742 mmplayer_t *player = 0;
7743 int prev_display_surface_type = 0;
7744 void *prev_display_overlay = NULL;
7748 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7749 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7751 player = MM_PLAYER_CAST(handle);
7753 /* check video sinkbin is created */
7754 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7755 LOGE("Videosink is already created");
7756 return MM_ERROR_NONE;
7759 LOGD("videosink element is not yet ready");
7761 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7762 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7764 return MM_ERROR_INVALID_ARGUMENT;
7767 /* load previous attributes */
7768 if (player->attrs) {
7769 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7770 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7771 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7772 if (prev_display_surface_type == surface_type) {
7773 LOGD("incoming display surface type is same as previous one, do nothing..");
7775 return MM_ERROR_NONE;
7778 LOGE("failed to load attributes");
7780 return MM_ERROR_PLAYER_INTERNAL;
7783 /* videobin is not created yet, so we just set attributes related to display surface */
7784 LOGD("store display attribute for given surface type(%d)", surface_type);
7785 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7786 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7787 if (mm_attrs_commit_all(player->attrs)) {
7788 LOGE("failed to commit attribute");
7790 return MM_ERROR_PLAYER_INTERNAL;
7794 return MM_ERROR_NONE;
7797 /* Note : if silent is true, then subtitle would not be displayed. :*/
7799 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7801 mmplayer_t *player = (mmplayer_t *)hplayer;
7805 /* check player handle */
7806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7808 player->set_mode.subtitle_off = silent;
7810 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7814 return MM_ERROR_NONE;
7818 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7820 mmplayer_gst_element_t *mainbin = NULL;
7821 mmplayer_gst_element_t *textbin = NULL;
7822 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7823 GstState current_state = GST_STATE_VOID_PENDING;
7824 GstState element_state = GST_STATE_VOID_PENDING;
7825 GstState element_pending_state = GST_STATE_VOID_PENDING;
7827 GstEvent *event = NULL;
7828 int result = MM_ERROR_NONE;
7830 GstClock *curr_clock = NULL;
7831 GstClockTime base_time, start_time, curr_time;
7836 /* check player handle */
7837 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7839 player->pipeline->mainbin &&
7840 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7842 mainbin = player->pipeline->mainbin;
7843 textbin = player->pipeline->textbin;
7845 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7847 // sync clock with current pipeline
7848 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7849 curr_time = gst_clock_get_time(curr_clock);
7851 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7852 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7854 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7855 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7857 if (current_state > GST_STATE_READY) {
7858 // sync state with current pipeline
7859 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7860 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7861 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7863 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7864 if (GST_STATE_CHANGE_FAILURE == ret) {
7865 LOGE("fail to state change.");
7866 result = MM_ERROR_PLAYER_INTERNAL;
7870 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7871 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7874 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7875 gst_object_unref(curr_clock);
7878 // seek to current position
7879 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7880 result = MM_ERROR_PLAYER_INVALID_STATE;
7881 LOGE("gst_element_query_position failed, invalid state");
7885 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7886 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);
7888 _mmplayer_gst_send_event_to_sink(player, event);
7890 result = MM_ERROR_PLAYER_INTERNAL;
7891 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7895 /* sync state with current pipeline */
7896 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7897 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7898 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7900 return MM_ERROR_NONE;
7903 /* release text pipeline resource */
7904 player->textsink_linked = 0;
7906 /* release signal */
7907 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7909 /* release textbin with it's childs */
7910 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7911 MMPLAYER_FREEIF(player->pipeline->textbin);
7912 player->pipeline->textbin = NULL;
7914 /* release subtitle elem */
7915 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7916 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7922 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7924 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7925 GstState current_state = GST_STATE_VOID_PENDING;
7927 MMHandleType attrs = 0;
7928 mmplayer_gst_element_t *mainbin = NULL;
7929 mmplayer_gst_element_t *textbin = NULL;
7931 gchar *subtitle_uri = NULL;
7932 int result = MM_ERROR_NONE;
7933 const gchar *charset = NULL;
7937 /* check player handle */
7938 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7940 player->pipeline->mainbin &&
7941 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7942 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7944 mainbin = player->pipeline->mainbin;
7945 textbin = player->pipeline->textbin;
7947 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7948 if (current_state < GST_STATE_READY) {
7949 result = MM_ERROR_PLAYER_INVALID_STATE;
7950 LOGE("Pipeline is not in proper state");
7954 attrs = MMPLAYER_GET_ATTRS(player);
7956 LOGE("cannot get content attribute");
7957 result = MM_ERROR_PLAYER_INTERNAL;
7961 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7962 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7963 LOGE("subtitle uri is not proper filepath");
7964 result = MM_ERROR_PLAYER_INVALID_URI;
7968 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7969 LOGE("failed to get storage info of subtitle path");
7970 result = MM_ERROR_PLAYER_INVALID_URI;
7974 LOGD("old subtitle file path is [%s]", subtitle_uri);
7975 LOGD("new subtitle file path is [%s]", filepath);
7977 if (!strcmp(filepath, subtitle_uri)) {
7978 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7981 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7982 if (mm_attrs_commit_all(player->attrs)) {
7983 LOGE("failed to commit.");
7988 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7989 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7990 player->subtitle_language_list = NULL;
7991 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7993 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7994 if (ret != GST_STATE_CHANGE_SUCCESS) {
7995 LOGE("failed to change state of textbin to READY");
7996 result = MM_ERROR_PLAYER_INTERNAL;
8000 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8001 if (ret != GST_STATE_CHANGE_SUCCESS) {
8002 LOGE("failed to change state of subparse to READY");
8003 result = MM_ERROR_PLAYER_INTERNAL;
8007 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8008 if (ret != GST_STATE_CHANGE_SUCCESS) {
8009 LOGE("failed to change state of filesrc to READY");
8010 result = MM_ERROR_PLAYER_INTERNAL;
8014 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8016 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8018 charset = _mmplayer_get_charset(filepath);
8020 LOGD("detected charset is %s", charset);
8021 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8024 result = _mmplayer_sync_subtitle_pipeline(player);
8031 /* API to switch between external subtitles */
8033 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8035 int result = MM_ERROR_NONE;
8036 mmplayer_t *player = (mmplayer_t *)hplayer;
8041 /* check player handle */
8042 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8044 /* filepath can be null in idle state */
8046 /* check file path */
8047 if ((path = strstr(filepath, "file://")))
8048 result = _mmplayer_exist_file_path(path + 7);
8050 result = _mmplayer_exist_file_path(filepath);
8052 if (result != MM_ERROR_NONE) {
8053 LOGE("invalid subtitle path 0x%X", result);
8054 return result; /* file not found or permission denied */
8058 if (!player->pipeline) {
8060 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8061 if (mm_attrs_commit_all(player->attrs)) {
8062 LOGE("failed to commit"); /* subtitle path will not be created */
8063 return MM_ERROR_PLAYER_INTERNAL;
8066 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8067 /* check filepath */
8068 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8070 if (!__mmplayer_check_subtitle(player)) {
8071 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8072 if (mm_attrs_commit_all(player->attrs)) {
8073 LOGE("failed to commit");
8074 return MM_ERROR_PLAYER_INTERNAL;
8077 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8078 LOGE("fail to create text pipeline");
8079 return MM_ERROR_PLAYER_INTERNAL;
8082 result = _mmplayer_sync_subtitle_pipeline(player);
8084 result = __mmplayer_change_external_subtitle_language(player, filepath);
8087 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8088 player->is_external_subtitle_added_now = TRUE;
8090 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8091 if (!player->subtitle_language_list) {
8092 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8093 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8094 LOGW("subtitle language list is not updated yet");
8096 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8104 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8106 int result = MM_ERROR_NONE;
8107 gchar *change_pad_name = NULL;
8108 GstPad *sinkpad = NULL;
8109 mmplayer_gst_element_t *mainbin = NULL;
8110 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8111 GstCaps *caps = NULL;
8112 gint total_track_num = 0;
8116 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8117 MM_ERROR_PLAYER_NOT_INITIALIZED);
8119 LOGD("Change Track(%d) to %d", type, index);
8121 mainbin = player->pipeline->mainbin;
8123 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8124 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8125 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8126 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8128 /* Changing Video Track is not supported. */
8129 LOGE("Track Type Error");
8133 if (mainbin[elem_idx].gst == NULL) {
8134 result = MM_ERROR_PLAYER_NO_OP;
8135 LOGD("Req track doesn't exist");
8139 total_track_num = player->selector[type].total_track_num;
8140 if (total_track_num <= 0) {
8141 result = MM_ERROR_PLAYER_NO_OP;
8142 LOGD("Language list is not available");
8146 if ((index < 0) || (index >= total_track_num)) {
8147 result = MM_ERROR_INVALID_ARGUMENT;
8148 LOGD("Not a proper index : %d", index);
8152 /*To get the new pad from the selector*/
8153 change_pad_name = g_strdup_printf("sink_%u", index);
8154 if (change_pad_name == NULL) {
8155 result = MM_ERROR_PLAYER_INTERNAL;
8156 LOGD("Pad does not exists");
8160 LOGD("new active pad name: %s", change_pad_name);
8162 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8163 if (sinkpad == NULL) {
8164 LOGD("sinkpad is NULL");
8165 result = MM_ERROR_PLAYER_INTERNAL;
8169 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8170 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8172 caps = gst_pad_get_current_caps(sinkpad);
8173 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8176 gst_object_unref(sinkpad);
8178 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8179 __mmplayer_set_audio_attrs(player, caps);
8182 MMPLAYER_FREEIF(change_pad_name);
8187 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8189 int result = MM_ERROR_NONE;
8190 mmplayer_t *player = NULL;
8191 mmplayer_gst_element_t *mainbin = NULL;
8193 gint current_active_index = 0;
8195 GstState current_state = GST_STATE_VOID_PENDING;
8196 GstEvent *event = NULL;
8201 player = (mmplayer_t *)hplayer;
8202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8204 if (!player->pipeline) {
8205 LOGE("Track %d pre setting -> %d", type, index);
8207 player->selector[type].active_pad_index = index;
8211 mainbin = player->pipeline->mainbin;
8213 current_active_index = player->selector[type].active_pad_index;
8215 /*If index is same as running index no need to change the pad*/
8216 if (current_active_index == index)
8219 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8220 result = MM_ERROR_PLAYER_INVALID_STATE;
8224 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8225 if (current_state < GST_STATE_PAUSED) {
8226 result = MM_ERROR_PLAYER_INVALID_STATE;
8227 LOGW("Pipeline not in porper state");
8231 result = __mmplayer_change_selector_pad(player, type, index);
8232 if (result != MM_ERROR_NONE) {
8233 LOGE("change selector pad error");
8237 player->selector[type].active_pad_index = index;
8239 if (current_state == GST_STATE_PLAYING) {
8240 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8241 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8242 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8244 _mmplayer_gst_send_event_to_sink(player, event);
8246 result = MM_ERROR_PLAYER_INTERNAL;
8256 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8258 mmplayer_t *player = (mmplayer_t *)hplayer;
8262 /* check player handle */
8263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8265 *silent = player->set_mode.subtitle_off;
8267 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8271 return MM_ERROR_NONE;
8275 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8277 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8278 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8280 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8281 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8285 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8286 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8287 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8288 mmplayer_dump_t *dump_s;
8289 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8290 if (dump_s == NULL) {
8291 LOGE("malloc fail");
8295 dump_s->dump_element_file = NULL;
8296 dump_s->dump_pad = NULL;
8297 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8299 if (dump_s->dump_pad) {
8300 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8301 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]);
8302 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8303 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);
8304 /* add list for removed buffer probe and close FILE */
8305 player->dump_list = g_list_append(player->dump_list, dump_s);
8306 LOGD("%s sink pad added buffer probe for dump", factory_name);
8309 MMPLAYER_FREEIF(dump_s);
8310 LOGE("failed to get %s sink pad added", factory_name);
8317 static GstPadProbeReturn
8318 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8320 FILE *dump_data = (FILE *)u_data;
8322 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8323 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8325 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8327 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8329 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8331 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8333 gst_buffer_unmap(buffer, &probe_info);
8335 return GST_PAD_PROBE_OK;
8339 __mmplayer_release_dump_list(GList *dump_list)
8341 GList *d_list = dump_list;
8346 for (; d_list; d_list = g_list_next(d_list)) {
8347 mmplayer_dump_t *dump_s = d_list->data;
8348 if (dump_s->dump_pad) {
8349 if (dump_s->probe_handle_id)
8350 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8351 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8353 if (dump_s->dump_element_file) {
8354 fclose(dump_s->dump_element_file);
8355 dump_s->dump_element_file = NULL;
8357 MMPLAYER_FREEIF(dump_s);
8359 g_list_free(dump_list);
8364 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8366 mmplayer_t *player = (mmplayer_t *)hplayer;
8370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8371 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8373 *exist = (bool)player->has_closed_caption;
8377 return MM_ERROR_NONE;
8381 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8386 LOGD("unref internal gst buffer %p", buffer);
8388 gst_buffer_unref((GstBuffer *)buffer);
8395 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8397 mmplayer_t *player = (mmplayer_t *)hplayer;
8401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8402 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8404 if (MMPLAYER_IS_STREAMING(player))
8405 *timeout = (int)player->ini.live_state_change_timeout;
8407 *timeout = (int)player->ini.localplayback_state_change_timeout;
8409 LOGD("timeout = %d", *timeout);
8412 return MM_ERROR_NONE;
8416 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8420 MMPLAYER_RETURN_IF_FAIL(player);
8422 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8424 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8425 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8426 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8427 player->storage_info[i].id = -1;
8428 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8430 if (path_type != MMPLAYER_PATH_MAX)
8439 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8441 int ret = MM_ERROR_NONE;
8442 mmplayer_t *player = (mmplayer_t *)hplayer;
8443 MMMessageParamType msg_param = {0, };
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8448 LOGW("state changed storage %d:%d", id, state);
8450 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8451 return MM_ERROR_NONE;
8453 /* FIXME: text path should be handled seperately. */
8454 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8455 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8456 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8457 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8458 LOGW("external storage is removed");
8460 if (player->msg_posted == FALSE) {
8461 memset(&msg_param, 0, sizeof(MMMessageParamType));
8462 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8463 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8464 player->msg_posted = TRUE;
8467 /* unrealize the player */
8468 ret = _mmplayer_unrealize(hplayer);
8469 if (ret != MM_ERROR_NONE)
8470 LOGE("failed to unrealize");
8478 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8480 int ret = MM_ERROR_NONE;
8481 mmplayer_t *player = (mmplayer_t *)hplayer;
8482 int idx = 0, total = 0;
8483 gchar *result = NULL, *tmp = NULL;
8486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8487 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8489 total = *num = g_list_length(player->adaptive_info.var_list);
8491 LOGW("There is no stream variant info.");
8495 result = g_strdup("");
8496 for (idx = 0 ; idx < total ; idx++) {
8497 stream_variant_t *v_data = NULL;
8498 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8501 gchar data[64] = {0};
8502 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8504 tmp = g_strconcat(result, data, NULL);
8508 LOGW("There is no variant data in %d", idx);
8513 *var_info = (char *)result;
8515 LOGD("variant info %d:%s", *num, *var_info);
8521 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8523 int ret = MM_ERROR_NONE;
8524 mmplayer_t *player = (mmplayer_t *)hplayer;
8527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8529 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8531 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8532 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8533 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8535 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8536 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8537 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8538 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8540 /* FIXME: seek to current position for applying new variant limitation */
8549 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8551 int ret = MM_ERROR_NONE;
8552 mmplayer_t *player = (mmplayer_t *)hplayer;
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8558 *bandwidth = player->adaptive_info.limit.bandwidth;
8559 *width = player->adaptive_info.limit.width;
8560 *height = player->adaptive_info.limit.height;
8562 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8569 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8571 int ret = MM_ERROR_NONE;
8572 mmplayer_t *player = (mmplayer_t *)hplayer;
8575 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8576 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8577 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8579 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8581 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8582 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8583 else /* live case */
8584 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8586 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8593 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8595 #define IDX_FIRST_SW_CODEC 0
8596 mmplayer_t *player = (mmplayer_t *)hplayer;
8597 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8598 MMHandleType attrs = 0;
8601 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8603 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8604 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8605 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8607 switch (stream_type) {
8608 case MM_PLAYER_STREAM_TYPE_AUDIO:
8609 /* to support audio codec selection, codec info have to be added in ini file as below.
8610 audio codec element hw = xxxx
8611 audio codec element sw = avdec */
8612 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8613 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8614 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8615 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8616 LOGE("There is no audio codec info for codec_type %d", codec_type);
8617 return MM_ERROR_PLAYER_NO_OP;
8620 case MM_PLAYER_STREAM_TYPE_VIDEO:
8621 /* to support video codec selection, codec info have to be added in ini file as below.
8622 video codec element hw = omx
8623 video codec element sw = avdec */
8624 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8625 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8626 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8627 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8628 LOGE("There is no video codec info for codec_type %d", codec_type);
8629 return MM_ERROR_PLAYER_NO_OP;
8633 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8634 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8638 LOGD("update %s codec_type to %d", attr_name, codec_type);
8640 attrs = MMPLAYER_GET_ATTRS(player);
8641 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8643 if (mm_attrs_commit_all(player->attrs)) {
8644 LOGE("failed to commit codec_type attributes");
8645 return MM_ERROR_PLAYER_INTERNAL;
8649 return MM_ERROR_NONE;
8653 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8655 mmplayer_t *player = (mmplayer_t *)hplayer;
8656 GstElement *rg_vol_element = NULL;
8660 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8662 player->sound.rg_enable = enabled;
8664 /* just hold rgvolume enable value if pipeline is not ready */
8665 if (!player->pipeline || !player->pipeline->audiobin) {
8666 LOGD("pipeline is not ready. holding rgvolume enable value");
8667 return MM_ERROR_NONE;
8670 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8672 if (!rg_vol_element) {
8673 LOGD("rgvolume element is not created");
8674 return MM_ERROR_PLAYER_INTERNAL;
8678 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8680 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8684 return MM_ERROR_NONE;
8688 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8690 mmplayer_t *player = (mmplayer_t *)hplayer;
8691 GstElement *rg_vol_element = NULL;
8692 gboolean enable = FALSE;
8696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8697 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8699 /* just hold enable_rg value if pipeline is not ready */
8700 if (!player->pipeline || !player->pipeline->audiobin) {
8701 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8702 *enabled = player->sound.rg_enable;
8703 return MM_ERROR_NONE;
8706 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8708 if (!rg_vol_element) {
8709 LOGD("rgvolume element is not created");
8710 return MM_ERROR_PLAYER_INTERNAL;
8713 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8714 *enabled = (bool)enable;
8718 return MM_ERROR_NONE;
8722 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8724 mmplayer_t *player = (mmplayer_t *)hplayer;
8725 MMHandleType attrs = 0;
8726 void *handle = NULL;
8727 int ret = MM_ERROR_NONE;
8731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 attrs = MMPLAYER_GET_ATTRS(player);
8734 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8736 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8738 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8739 return MM_ERROR_PLAYER_INTERNAL;
8742 player->video_roi.scale_x = scale_x;
8743 player->video_roi.scale_y = scale_y;
8744 player->video_roi.scale_width = scale_width;
8745 player->video_roi.scale_height = scale_height;
8747 /* check video sinkbin is created */
8748 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8749 return MM_ERROR_NONE;
8751 if (!gst_video_overlay_set_video_roi_area(
8752 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8753 scale_x, scale_y, scale_width, scale_height))
8754 ret = MM_ERROR_PLAYER_INTERNAL;
8756 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8757 scale_x, scale_y, scale_width, scale_height);
8765 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8767 mmplayer_t *player = (mmplayer_t *)hplayer;
8768 int ret = MM_ERROR_NONE;
8772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8773 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8775 *scale_x = player->video_roi.scale_x;
8776 *scale_y = player->video_roi.scale_y;
8777 *scale_width = player->video_roi.scale_width;
8778 *scale_height = player->video_roi.scale_height;
8780 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8781 *scale_x, *scale_y, *scale_width, *scale_height);
8787 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8789 mmplayer_t* player = (mmplayer_t*)hplayer;
8793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8795 player->client_pid = pid;
8797 LOGD("client pid[%d] %p", pid, player);
8801 return MM_ERROR_NONE;
8805 __mmplayer_update_duration_value(mmplayer_t *player)
8807 gboolean ret = FALSE;
8808 gint64 dur_nsec = 0;
8809 LOGD("try to update duration");
8811 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8812 player->duration = dur_nsec;
8813 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8817 if (player->duration < 0) {
8818 LOGW("duration is Non-Initialized !!!");
8819 player->duration = 0;
8822 /* update streaming service type */
8823 player->streaming_type = _mmplayer_get_stream_service_type(player);
8825 /* check duration is OK */
8826 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8827 /* FIXIT : find another way to get duration here. */
8828 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8834 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8836 /* update audio params
8837 NOTE : We need original audio params and it can be only obtained from src pad of audio
8838 decoder. Below code only valid when we are not using 'resampler' just before
8839 'audioconverter'. */
8840 GstCaps *caps_a = NULL;
8842 gint samplerate = 0, channels = 0;
8843 GstStructure *p = NULL;
8844 GstElement *aconv = NULL;
8846 LOGD("try to update audio attrs");
8848 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8850 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8851 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8852 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8853 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8855 LOGE("there is no audio converter");
8859 pad = gst_element_get_static_pad(aconv, "sink");
8862 LOGW("failed to get pad from audio converter");
8866 caps_a = gst_pad_get_current_caps(pad);
8868 LOGW("not ready to get audio caps");
8869 gst_object_unref(pad);
8873 p = gst_caps_get_structure(caps_a, 0);
8875 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8877 gst_structure_get_int(p, "rate", &samplerate);
8878 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8880 gst_structure_get_int(p, "channels", &channels);
8881 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8883 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8885 gst_caps_unref(caps_a);
8886 gst_object_unref(pad);
8892 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8894 LOGD("try to update video attrs");
8896 GstCaps *caps_v = NULL;
8900 GstStructure *p = NULL;
8902 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8903 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8905 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8907 LOGD("no videosink sink pad");
8911 caps_v = gst_pad_get_current_caps(pad);
8912 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8913 if (!caps_v && player->v_stream_caps) {
8914 caps_v = player->v_stream_caps;
8915 gst_caps_ref(caps_v);
8919 LOGD("no negitiated caps from videosink");
8920 gst_object_unref(pad);
8924 p = gst_caps_get_structure(caps_v, 0);
8925 gst_structure_get_int(p, "width", &width);
8926 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8928 gst_structure_get_int(p, "height", &height);
8929 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8931 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8933 SECURE_LOGD("width : %d height : %d", width, height);
8935 gst_caps_unref(caps_v);
8936 gst_object_unref(pad);
8939 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8940 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8947 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8949 gboolean ret = FALSE;
8950 guint64 data_size = 0;
8954 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8955 if (!player->duration)
8958 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8959 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8960 if (stat(path, &sb) == 0)
8961 data_size = (guint64)sb.st_size;
8963 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8964 data_size = player->http_content_size;
8967 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8970 guint64 bitrate = 0;
8971 guint64 msec_dur = 0;
8973 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8975 bitrate = data_size * 8 * 1000 / msec_dur;
8976 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8977 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8981 LOGD("player duration is less than 0");
8985 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8986 if (player->total_bitrate) {
8987 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8996 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8998 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8999 data->uri_type = uri_type;
9003 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9005 int ret = MM_ERROR_PLAYER_INVALID_URI;
9007 char *buffer = NULL;
9008 char *seperator = strchr(path, ',');
9009 char ext[100] = {0,}, size[100] = {0,};
9012 if ((buffer = strstr(path, "ext="))) {
9013 buffer += strlen("ext=");
9015 if (strlen(buffer)) {
9016 strncpy(ext, buffer, 99);
9018 if ((seperator = strchr(ext, ','))
9019 || (seperator = strchr(ext, ' '))
9020 || (seperator = strchr(ext, '\0'))) {
9021 seperator[0] = '\0';
9026 if ((buffer = strstr(path, "size="))) {
9027 buffer += strlen("size=");
9029 if (strlen(buffer) > 0) {
9030 strncpy(size, buffer, 99);
9032 if ((seperator = strchr(size, ','))
9033 || (seperator = strchr(size, ' '))
9034 || (seperator = strchr(size, '\0'))) {
9035 seperator[0] = '\0';
9038 mem_size = atoi(size);
9043 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9045 if (mem_size && param) {
9046 if (data->input_mem.buf)
9047 free(data->input_mem.buf);
9048 data->input_mem.buf = malloc(mem_size);
9050 if (data->input_mem.buf) {
9051 memcpy(data->input_mem.buf, param, mem_size);
9052 data->input_mem.len = mem_size;
9053 ret = MM_ERROR_NONE;
9055 LOGE("failed to alloc mem %d", mem_size);
9056 ret = MM_ERROR_PLAYER_INTERNAL;
9059 data->input_mem.offset = 0;
9060 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9067 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9069 gchar *location = NULL;
9072 int ret = MM_ERROR_NONE;
9074 if ((path = strstr(uri, "file://"))) {
9075 location = g_filename_from_uri(uri, NULL, &err);
9076 if (!location || (err != NULL)) {
9077 LOGE("Invalid URI '%s' for filesrc: %s", path,
9078 (err != NULL) ? err->message : "unknown error");
9082 MMPLAYER_FREEIF(location);
9084 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9085 return MM_ERROR_PLAYER_INVALID_URI;
9087 LOGD("path from uri: %s", location);
9090 path = (location != NULL) ? (location) : ((char *)uri);
9093 ret = _mmplayer_exist_file_path(path);
9095 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9096 if (ret == MM_ERROR_NONE) {
9097 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9098 if (_mmplayer_is_sdp_file(path)) {
9099 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9100 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9102 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9104 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9105 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9107 LOGE("invalid uri, could not play..");
9108 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9111 MMPLAYER_FREEIF(location);
9116 static mmplayer_video_decoded_data_info_t *
9117 __mmplayer_create_stream_from_pad(GstPad *pad)
9119 GstCaps *caps = NULL;
9120 GstStructure *structure = NULL;
9121 unsigned int fourcc = 0;
9122 const gchar *string_format = NULL;
9123 mmplayer_video_decoded_data_info_t *stream = NULL;
9125 MMPixelFormatType format;
9128 caps = gst_pad_get_current_caps(pad);
9130 LOGE("Caps is NULL.");
9135 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9137 structure = gst_caps_get_structure(caps, 0);
9138 gst_structure_get_int(structure, "width", &width);
9139 gst_structure_get_int(structure, "height", &height);
9140 string_format = gst_structure_get_string(structure, "format");
9143 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9144 format = _mmplayer_get_pixtype(fourcc);
9145 gst_video_info_from_caps(&info, caps);
9146 gst_caps_unref(caps);
9149 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9150 LOGE("Wrong condition!!");
9154 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9156 LOGE("failed to alloc mem for video data");
9160 stream->width = width;
9161 stream->height = height;
9162 stream->format = format;
9163 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9169 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9171 unsigned int pitch = 0;
9172 unsigned int size = 0;
9174 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9177 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9178 bo = gst_tizen_memory_get_bos(mem, index);
9180 stream->bo[index] = tbm_bo_ref(bo);
9182 LOGE("failed to get bo for index %d", index);
9185 for (index = 0; index < stream->plane_num; index++) {
9186 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9187 stream->stride[index] = pitch;
9189 stream->elevation[index] = size / pitch;
9191 stream->elevation[index] = stream->height;
9196 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9198 if (stream->format == MM_PIXEL_FORMAT_I420) {
9199 int ret = TBM_SURFACE_ERROR_NONE;
9200 tbm_surface_h surface;
9201 tbm_surface_info_s info;
9203 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9205 ret = tbm_surface_get_info(surface, &info);
9206 if (ret != TBM_SURFACE_ERROR_NONE) {
9207 tbm_surface_destroy(surface);
9211 tbm_surface_destroy(surface);
9212 stream->stride[0] = info.planes[0].stride;
9213 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9214 stream->stride[1] = info.planes[1].stride;
9215 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9216 stream->stride[2] = info.planes[2].stride;
9217 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9218 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9219 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9220 stream->stride[0] = stream->width * 4;
9221 stream->elevation[0] = stream->height;
9222 stream->bo_size = stream->stride[0] * stream->height;
9224 LOGE("Not support format %d", stream->format);
9232 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9234 tbm_bo_handle thandle;
9236 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9237 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9238 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9242 unsigned char *src = NULL;
9243 unsigned char *dest = NULL;
9244 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9246 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9248 LOGE("fail to gst_memory_map");
9252 if (!mapinfo.data) {
9253 LOGE("data pointer is wrong");
9257 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9258 if (!stream->bo[0]) {
9259 LOGE("Fail to tbm_bo_alloc!!");
9263 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9265 LOGE("thandle pointer is wrong");
9269 if (stream->format == MM_PIXEL_FORMAT_I420) {
9270 src_stride[0] = GST_ROUND_UP_4(stream->width);
9271 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9272 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9273 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9276 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9277 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9279 for (i = 0; i < 3; i++) {
9280 src = mapinfo.data + src_offset[i];
9281 dest = thandle.ptr + dest_offset[i];
9286 for (j = 0; j < stream->height >> k; j++) {
9287 memcpy(dest, src, stream->width>>k);
9288 src += src_stride[i];
9289 dest += stream->stride[i];
9292 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9293 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9295 LOGE("Not support format %d", stream->format);
9299 tbm_bo_unmap(stream->bo[0]);
9300 gst_memory_unmap(mem, &mapinfo);
9306 tbm_bo_unmap(stream->bo[0]);
9309 gst_memory_unmap(mem, &mapinfo);
9315 __mmplayer_set_pause_state(mmplayer_t *player)
9317 if (player->sent_bos)
9320 /* rtsp case, get content attrs by GstMessage */
9321 if (MMPLAYER_IS_RTSP_STREAMING(player))
9324 /* it's first time to update all content attrs. */
9325 _mmplayer_update_content_attrs(player, ATTR_ALL);
9329 __mmplayer_set_playing_state(mmplayer_t *player)
9331 gchar *audio_codec = NULL;
9333 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9334 /* initialize because auto resume is done well. */
9335 player->resumed_by_rewind = FALSE;
9336 player->playback_rate = 1.0;
9339 if (player->sent_bos)
9342 /* try to get content metadata */
9344 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9345 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9346 * legacy mmfw-player api
9348 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9350 if ((player->cmd == MMPLAYER_COMMAND_START)
9351 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9352 __mmplayer_handle_missed_plugin(player);
9355 /* check audio codec field is set or not
9356 * we can get it from typefinder or codec's caps.
9358 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9360 /* The codec format can't be sent for audio only case like amr, mid etc.
9361 * Because, parser don't make related TAG.
9362 * So, if it's not set yet, fill it with found data.
9365 if (g_strrstr(player->type, "audio/midi"))
9366 audio_codec = "MIDI";
9367 else if (g_strrstr(player->type, "audio/x-amr"))
9368 audio_codec = "AMR";
9369 else if (g_strrstr(player->type, "audio/mpeg")
9370 && !g_strrstr(player->type, "mpegversion=(int)1"))
9371 audio_codec = "AAC";
9373 audio_codec = "unknown";
9375 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9377 if (mm_attrs_commit_all(player->attrs))
9378 LOGE("failed to update attributes");
9380 LOGD("set audio codec type with caps");