4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
278 if (mm_attrs_commit_all(attrs)) {
279 LOGE("failed to update attributes");
289 _mmplayer_get_stream_service_type(mmplayer_t *player)
291 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
297 player->pipeline->mainbin &&
298 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
299 STREAMING_SERVICE_NONE);
301 /* streaming service type if streaming */
302 if (!MMPLAYER_IS_STREAMING(player))
303 return STREAMING_SERVICE_NONE;
305 streaming_type = (player->duration == 0) ?
306 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
308 switch (streaming_type) {
309 case STREAMING_SERVICE_LIVE:
310 LOGD("it's live streaming");
312 case STREAMING_SERVICE_VOD:
313 LOGD("it's vod streaming");
316 LOGE("should not get here");
322 return streaming_type;
325 /* this function sets the player state and also report
326 * it to applicaton by calling callback function
329 _mmplayer_set_state(mmplayer_t *player, int state)
331 MMMessageParamType msg = {0, };
333 MMPLAYER_RETURN_IF_FAIL(player);
335 if (MMPLAYER_CURRENT_STATE(player) == state) {
336 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
337 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
341 /* update player states */
342 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
343 MMPLAYER_CURRENT_STATE(player) = state;
345 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
346 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
349 MMPLAYER_PRINT_STATE(player);
351 switch (MMPLAYER_CURRENT_STATE(player)) {
352 case MM_PLAYER_STATE_NULL:
353 case MM_PLAYER_STATE_READY:
355 case MM_PLAYER_STATE_PAUSED:
356 __mmplayer_set_pause_state(player);
358 case MM_PLAYER_STATE_PLAYING:
359 __mmplayer_set_playing_state(player);
361 case MM_PLAYER_STATE_NONE:
363 LOGW("invalid target state, there is nothing to do.");
368 /* post message to application */
369 if (MMPLAYER_TARGET_STATE(player) == state) {
370 /* fill the message with state of player */
371 msg.union_type = MM_MSG_UNION_STATE;
372 msg.state.previous = MMPLAYER_PREV_STATE(player);
373 msg.state.current = MMPLAYER_CURRENT_STATE(player);
375 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
377 /* state changed by resource callback */
378 if (player->interrupted_by_resource)
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
380 else /* state changed by usecase */
381 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
384 LOGD("intermediate state, do nothing.");
385 MMPLAYER_PRINT_STATE(player);
389 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
390 && !player->sent_bos) {
391 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
392 player->sent_bos = TRUE;
399 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
401 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
402 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
404 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
406 LOGD("incomming command : %d ", command);
408 current_state = MMPLAYER_CURRENT_STATE(player);
409 pending_state = MMPLAYER_PENDING_STATE(player);
411 MMPLAYER_PRINT_STATE(player);
414 case MMPLAYER_COMMAND_CREATE:
416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
418 if (current_state == MM_PLAYER_STATE_NULL ||
419 current_state == MM_PLAYER_STATE_READY ||
420 current_state == MM_PLAYER_STATE_PAUSED ||
421 current_state == MM_PLAYER_STATE_PLAYING)
426 case MMPLAYER_COMMAND_DESTROY:
428 /* destroy can called anytime */
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
434 case MMPLAYER_COMMAND_REALIZE:
436 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
438 if (pending_state != MM_PLAYER_STATE_NONE) {
441 /* need ready state to realize */
442 if (current_state == MM_PLAYER_STATE_READY)
445 if (current_state != MM_PLAYER_STATE_NULL)
451 case MMPLAYER_COMMAND_UNREALIZE:
453 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
455 if (current_state == MM_PLAYER_STATE_NULL)
460 case MMPLAYER_COMMAND_START:
462 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
464 if (pending_state == MM_PLAYER_STATE_NONE) {
465 if (current_state == MM_PLAYER_STATE_PLAYING)
467 else if (current_state != MM_PLAYER_STATE_READY &&
468 current_state != MM_PLAYER_STATE_PAUSED)
470 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
472 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
473 LOGD("player is going to paused state, just change the pending state as playing");
480 case MMPLAYER_COMMAND_STOP:
482 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
484 if (current_state == MM_PLAYER_STATE_READY)
487 /* need playing/paused state to stop */
488 if (current_state != MM_PLAYER_STATE_PLAYING &&
489 current_state != MM_PLAYER_STATE_PAUSED)
494 case MMPLAYER_COMMAND_PAUSE:
496 if (MMPLAYER_IS_LIVE_STREAMING(player))
499 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
500 goto NOT_COMPLETED_SEEK;
502 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
504 if (pending_state == MM_PLAYER_STATE_NONE) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
507 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
509 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
511 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
512 if (current_state == MM_PLAYER_STATE_PAUSED)
513 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
520 case MMPLAYER_COMMAND_RESUME:
522 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
523 goto NOT_COMPLETED_SEEK;
525 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
527 if (pending_state == MM_PLAYER_STATE_NONE) {
528 if (current_state == MM_PLAYER_STATE_PLAYING)
530 else if (current_state != MM_PLAYER_STATE_PAUSED)
532 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
534 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
535 LOGD("player is going to paused state, just change the pending state as playing");
545 player->cmd = command;
547 return MM_ERROR_NONE;
550 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
551 MMPLAYER_STATE_GET_NAME(current_state), command);
552 return MM_ERROR_PLAYER_INVALID_STATE;
555 LOGW("not completed seek");
556 return MM_ERROR_PLAYER_DOING_SEEK;
559 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
560 return MM_ERROR_PLAYER_NO_OP;
563 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
564 return MM_ERROR_PLAYER_NO_OP;
567 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
569 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
570 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
573 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
576 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
577 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
579 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
580 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
583 LOGE("invalid mmplayer resource type %d", type);
584 return MM_ERROR_PLAYER_INTERNAL;
587 if (player->hw_resource[type] != NULL) {
588 LOGD("[%d type] resource was already acquired", type);
589 return MM_ERROR_NONE;
592 LOGD("mark for acquire [%d type] resource", type);
593 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
594 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
600 rm_ret = mm_resource_manager_commit(player->resource_manager);
601 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
602 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
603 return MM_ERROR_PLAYER_INTERNAL;
607 return MM_ERROR_NONE;
610 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
612 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
616 if (player->hw_resource[type] == NULL) {
617 LOGD("there is no acquired [%d type] resource", type);
618 return MM_ERROR_NONE;
621 LOGD("mark for release [%d type] resource", type);
622 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
623 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
624 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
625 return MM_ERROR_PLAYER_INTERNAL;
628 player->hw_resource[type] = NULL;
630 rm_ret = mm_resource_manager_commit(player->resource_manager);
631 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633 return MM_ERROR_PLAYER_INTERNAL;
637 return MM_ERROR_NONE;
641 __mmplayer_initialize_gapless_play(mmplayer_t *player)
647 player->smooth_streaming = FALSE;
648 player->videodec_linked = 0;
649 player->audiodec_linked = 0;
650 player->textsink_linked = 0;
651 player->is_external_subtitle_present = FALSE;
652 player->is_external_subtitle_added_now = FALSE;
653 player->not_supported_codec = MISSING_PLUGIN_NONE;
654 player->can_support_codec = FOUND_PLUGIN_NONE;
655 player->pending_seek.is_pending = false;
656 player->pending_seek.pos = 0;
657 player->msg_posted = FALSE;
658 player->has_many_types = FALSE;
659 player->no_more_pad = FALSE;
660 player->not_found_demuxer = 0;
661 player->seek_state = MMPLAYER_SEEK_NONE;
662 player->is_subtitle_force_drop = FALSE;
663 player->play_subtitle = FALSE;
664 player->adjust_subtitle_pos = 0;
666 player->total_bitrate = 0;
667 player->total_maximum_bitrate = 0;
669 _mmplayer_track_initialize(player);
670 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
672 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
673 player->bitrate[i] = 0;
674 player->maximum_bitrate[i] = 0;
677 if (player->v_stream_caps) {
678 gst_caps_unref(player->v_stream_caps);
679 player->v_stream_caps = NULL;
682 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
684 /* clean found audio decoders */
685 if (player->audio_decoders) {
686 GList *a_dec = player->audio_decoders;
687 for (; a_dec; a_dec = g_list_next(a_dec)) {
688 gchar *name = a_dec->data;
689 MMPLAYER_FREEIF(name);
691 g_list_free(player->audio_decoders);
692 player->audio_decoders = NULL;
695 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
701 __mmplayer_gapless_play_thread(gpointer data)
703 mmplayer_t *player = (mmplayer_t *)data;
704 mmplayer_gst_element_t *mainbin = NULL;
706 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
709 while (!player->gapless_play_thread_exit) {
710 LOGD("gapless play thread started. waiting for signal.");
711 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
713 LOGD("reconfigure pipeline for gapless play.");
715 if (player->gapless_play_thread_exit) {
716 if (player->gapless.reconfigure) {
717 player->gapless.reconfigure = false;
718 MMPLAYER_PLAYBACK_UNLOCK(player);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 MMHandleType attrs = 0;
1350 gint active_index = 0;
1353 MMPLAYER_RETURN_IF_FAIL(player);
1355 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1357 /* change track to active pad */
1358 active_index = player->selector[type].active_pad_index;
1359 if ((active_index != DEFAULT_TRACK) &&
1360 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1361 LOGW("failed to change %d type track to %d", type, active_index);
1362 player->selector[type].active_pad_index = DEFAULT_TRACK;
1366 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1367 attrs = MMPLAYER_GET_ATTRS(player);
1369 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1370 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1372 if (mm_attrs_commit_all(attrs))
1373 LOGW("failed to commit attrs.");
1375 LOGW("cannot get content attribute");
1384 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1389 if (!audio_selector) {
1390 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1392 /* in case the source is changed, output can be changed. */
1393 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1394 LOGD("remove previous audiobin if it exist");
1396 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1397 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1399 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1400 MMPLAYER_FREEIF(player->pipeline->audiobin);
1403 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1404 __mmplayer_pipeline_complete(NULL, player);
1409 /* apply the audio track information */
1410 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1412 /* create audio sink path */
1413 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1414 LOGE("failed to create audio sink path");
1423 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1426 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1428 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1429 LOGD("text path is not supproted");
1433 /* apply the text track information */
1434 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1436 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1437 player->has_closed_caption = TRUE;
1439 /* create text decode path */
1440 player->no_more_pad = TRUE;
1442 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1443 LOGE("failed to create text sink path");
1452 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1454 gint64 dur_bytes = 0L;
1457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1458 player->pipeline->mainbin && player->streamer, FALSE);
1460 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1461 LOGE("fail to get duration.");
1463 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1464 * use file information was already set on Q2 when it was created. */
1465 _mm_player_streaming_set_queue2(player->streamer,
1466 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1467 TRUE, /* use_buffering */
1468 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1469 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1476 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1478 mmplayer_t *player = NULL;
1479 GstElement *video_selector = NULL;
1480 GstElement *audio_selector = NULL;
1481 GstElement *text_selector = NULL;
1484 player = (mmplayer_t *)data;
1486 LOGD("no-more-pad signal handling");
1488 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1489 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1490 LOGW("player is shutting down");
1494 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1495 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1496 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1497 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1498 LOGE("failed to set queue2 buffering");
1503 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1504 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1505 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1507 if (!video_selector && !audio_selector && !text_selector) {
1508 LOGW("there is no selector");
1509 player->no_more_pad = TRUE;
1513 /* create video path followed by video-select */
1514 if (video_selector && !audio_selector && !text_selector)
1515 player->no_more_pad = TRUE;
1517 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1520 /* create audio path followed by audio-select */
1521 if (audio_selector && !text_selector)
1522 player->no_more_pad = TRUE;
1524 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1527 /* create text path followed by text-select */
1528 __mmplayer_create_text_sink_path(player, text_selector);
1531 if (player->gapless.reconfigure) {
1532 player->gapless.reconfigure = FALSE;
1533 MMPLAYER_PLAYBACK_UNLOCK(player);
1540 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1542 gboolean ret = FALSE;
1543 GstElement *pipeline = NULL;
1544 GstPad *sinkpad = NULL;
1547 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1550 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1552 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1554 LOGE("failed to get pad from sinkbin");
1560 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1561 LOGE("failed to link sinkbin for reusing");
1562 goto EXIT; /* exit either pass or fail */
1566 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1567 LOGE("failed to set state(READY) to sinkbin");
1572 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1573 LOGE("failed to add sinkbin to pipeline");
1578 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1579 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1584 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1585 LOGE("failed to set state(PAUSED) to sinkbin");
1594 gst_object_unref(GST_OBJECT(sinkpad));
1602 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1604 mmplayer_t *player = NULL;
1605 GstCaps *caps = NULL;
1606 gchar *caps_str = NULL;
1607 GstStructure *str = NULL;
1608 const gchar *name = NULL;
1609 GstElement *sinkbin = NULL;
1610 gboolean reusing = FALSE;
1611 gboolean caps_ret = TRUE;
1612 gchar *sink_pad_name = "sink";
1615 player = (mmplayer_t *)data;
1618 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1619 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1621 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1625 caps_str = gst_caps_to_string(caps);
1627 LOGD("detected mimetype : %s", name);
1629 if (strstr(name, "audio")) {
1630 if (player->pipeline->audiobin == NULL) {
1631 const gchar *audio_format = gst_structure_get_string(str, "format");
1633 LOGD("original audio format %s", audio_format);
1634 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1637 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1638 LOGE("failed to create audiobin. continuing without audio");
1642 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1643 LOGD("creating audiobin success");
1646 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1647 LOGD("reusing audiobin");
1648 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1650 } else if (strstr(name, "video")) {
1651 /* 1. zero copy is updated at _decode_pad_added()
1652 * 2. NULL surface type is handled in _decode_pad_added() */
1653 LOGD("zero copy %d", player->set_mode.video_zc);
1654 if (player->pipeline->videobin == NULL) {
1655 int surface_type = 0;
1656 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1657 LOGD("display_surface_type (%d)", surface_type);
1659 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1660 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1661 LOGE("failed to acquire video overlay resource");
1665 player->interrupted_by_resource = FALSE;
1667 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1668 LOGE("failed to create videobin. continuing without video");
1672 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1673 LOGD("creating videosink bin success");
1676 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1677 LOGD("re-using videobin");
1678 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1680 } else if (strstr(name, "text")) {
1681 if (player->pipeline->textbin == NULL) {
1682 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1683 LOGE("failed to create text sink bin. continuing without text");
1687 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1688 player->textsink_linked = 1;
1689 LOGD("creating textsink bin success");
1691 if (!player->textsink_linked) {
1692 LOGD("re-using textbin");
1694 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1695 player->textsink_linked = 1;
1697 /* linked textbin exist which means that the external subtitle path exist already */
1698 LOGW("ignoring internal subtutle since external subtitle is available");
1701 sink_pad_name = "text_sink";
1703 LOGW("unknown mime type %s, ignoring it", name);
1707 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1710 LOGD("[handle: %p] success to create and link sink bin", player);
1712 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1713 * streaming task. if the task blocked, then buffer will not flow to the next element
1714 *(autoplugging element). so this is special hack for streaming. please try to remove it
1716 /* dec stream count. we can remove fakesink if it's zero */
1717 if (player->num_dynamic_pad)
1718 player->num_dynamic_pad--;
1720 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1722 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1723 __mmplayer_pipeline_complete(NULL, player);
1727 MMPLAYER_FREEIF(caps_str);
1730 gst_caps_unref(caps);
1736 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1738 int required_angle = 0; /* Angle required for straight view */
1739 int rotation_angle = 0;
1741 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1742 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1744 /* Counter clockwise */
1745 switch (orientation) {
1750 required_angle = 270;
1753 required_angle = 180;
1756 required_angle = 90;
1760 rotation_angle = display_angle + required_angle;
1761 if (rotation_angle >= 360)
1762 rotation_angle -= 360;
1764 /* chech if supported or not */
1765 if (rotation_angle % 90) {
1766 LOGD("not supported rotation angle = %d", rotation_angle);
1770 switch (rotation_angle) {
1772 *value = MM_DISPLAY_ROTATION_NONE;
1775 *value = MM_DISPLAY_ROTATION_90;
1778 *value = MM_DISPLAY_ROTATION_180;
1781 *value = MM_DISPLAY_ROTATION_270;
1785 LOGD("setting rotation property value : %d", *value);
1791 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1793 int display_rotation = 0;
1794 gchar *org_orient = NULL;
1795 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1798 LOGE("cannot get content attribute");
1799 return MM_ERROR_PLAYER_INTERNAL;
1802 if (display_angle) {
1803 /* update user roation */
1804 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1806 /* Counter clockwise */
1807 switch (display_rotation) {
1808 case MM_DISPLAY_ROTATION_NONE:
1811 case MM_DISPLAY_ROTATION_90:
1812 *display_angle = 90;
1814 case MM_DISPLAY_ROTATION_180:
1815 *display_angle = 180;
1817 case MM_DISPLAY_ROTATION_270:
1818 *display_angle = 270;
1821 LOGW("wrong angle type : %d", display_rotation);
1824 LOGD("check user angle: %d", *display_angle);
1828 /* Counter clockwise */
1829 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1832 if (!strcmp(org_orient, "rotate-90"))
1834 else if (!strcmp(org_orient, "rotate-180"))
1836 else if (!strcmp(org_orient, "rotate-270"))
1839 LOGD("original rotation is %s", org_orient);
1841 LOGD("content_video_orientation get fail");
1844 LOGD("check orientation: %d", *orientation);
1847 return MM_ERROR_NONE;
1850 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1852 int rotation_value = 0;
1853 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1854 int display_angle = 0;
1857 /* check video sinkbin is created */
1858 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1861 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1863 /* get rotation value to set */
1864 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1865 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1866 LOGD("set video param : rotate %d", rotation_value);
1869 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1871 MMHandleType attrs = 0;
1875 /* check video sinkbin is created */
1876 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1879 attrs = MMPLAYER_GET_ATTRS(player);
1880 MMPLAYER_RETURN_IF_FAIL(attrs);
1882 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1883 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1884 LOGD("set video param : visible %d", visible);
1887 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1889 MMHandleType attrs = 0;
1890 int display_method = 0;
1893 /* check video sinkbin is created */
1894 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1897 attrs = MMPLAYER_GET_ATTRS(player);
1898 MMPLAYER_RETURN_IF_FAIL(attrs);
1900 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1901 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1902 LOGD("set video param : method %d", display_method);
1905 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1907 MMHandleType attrs = 0;
1908 void *handle = NULL;
1911 /* check video sinkbin is created */
1912 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1915 attrs = MMPLAYER_GET_ATTRS(player);
1916 MMPLAYER_RETURN_IF_FAIL(attrs);
1917 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1919 gst_video_overlay_set_video_roi_area(
1920 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1921 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1922 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1923 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1927 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1929 MMHandleType attrs = 0;
1930 void *handle = NULL;
1934 int win_roi_width = 0;
1935 int win_roi_height = 0;
1938 /* check video sinkbin is created */
1939 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1942 attrs = MMPLAYER_GET_ATTRS(player);
1943 MMPLAYER_RETURN_IF_FAIL(attrs);
1945 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1948 /* It should be set after setting window */
1949 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1950 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1951 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1952 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1954 /* After setting window handle, set display roi area */
1955 gst_video_overlay_set_display_roi_area(
1956 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1957 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1958 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1959 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1963 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1965 MMHandleType attrs = 0;
1966 void *handle = NULL;
1968 /* check video sinkbin is created */
1969 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1972 attrs = MMPLAYER_GET_ATTRS(player);
1973 MMPLAYER_RETURN_IF_FAIL(attrs);
1975 /* common case if using overlay surface */
1976 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1979 /* default is using wl_surface_id */
1980 unsigned int wl_surface_id = 0;
1981 wl_surface_id = *(int *)handle;
1982 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1983 gst_video_overlay_set_wl_window_wl_surface_id(
1984 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1987 /* FIXIT : is it error case? */
1988 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1993 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1995 gboolean update_all_param = FALSE;
1999 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2000 LOGW("videosink is not ready yet");
2001 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2004 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2005 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2006 return MM_ERROR_PLAYER_INTERNAL;
2009 LOGD("param_name : %s", param_name);
2010 if (!g_strcmp0(param_name, "update_all_param"))
2011 update_all_param = TRUE;
2013 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2014 __mmplayer_video_param_set_display_overlay(player);
2015 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2016 __mmplayer_video_param_set_display_method(player);
2017 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2018 __mmplayer_video_param_set_display_visible(player);
2019 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2020 __mmplayer_video_param_set_display_rotation(player);
2021 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2022 __mmplayer_video_param_set_roi_area(player);
2023 if (update_all_param)
2024 __mmplayer_video_param_set_video_roi_area(player);
2028 return MM_ERROR_NONE;
2032 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2034 gboolean disable_overlay = FALSE;
2035 mmplayer_t *player = (mmplayer_t *)hplayer;
2038 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2039 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2040 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2041 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2043 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2044 LOGW("Display control is not supported");
2045 return MM_ERROR_PLAYER_INTERNAL;
2048 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2050 if (audio_only == (bool)disable_overlay) {
2051 LOGE("It's the same with current setting: (%d)", audio_only);
2052 return MM_ERROR_NONE;
2056 LOGE("disable overlay");
2057 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2059 /* release overlay resource */
2060 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2061 LOGE("failed to release overlay resource");
2065 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2066 LOGE("failed to acquire video overlay resource");
2069 player->interrupted_by_resource = FALSE;
2071 LOGD("enable overlay");
2072 __mmplayer_video_param_set_display_overlay(player);
2073 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2078 return MM_ERROR_NONE;
2082 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2084 mmplayer_t *player = (mmplayer_t *)hplayer;
2085 gboolean disable_overlay = FALSE;
2089 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2090 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2091 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2092 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2093 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2095 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2096 LOGW("Display control is not supported");
2097 return MM_ERROR_PLAYER_INTERNAL;
2100 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2102 *paudio_only = (bool)disable_overlay;
2104 LOGD("audio_only : %d", *paudio_only);
2108 return MM_ERROR_NONE;
2112 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2114 GList *bucket = element_bucket;
2115 mmplayer_gst_element_t *element = NULL;
2116 mmplayer_gst_element_t *prv_element = NULL;
2117 GstElement *tee_element = NULL;
2118 gint successful_link_count = 0;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2124 prv_element = (mmplayer_gst_element_t *)bucket->data;
2125 bucket = bucket->next;
2127 for (; bucket; bucket = bucket->next) {
2128 element = (mmplayer_gst_element_t *)bucket->data;
2130 if (element && element->gst) {
2131 if (prv_element && prv_element->gst) {
2132 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2134 prv_element->gst = tee_element;
2136 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2137 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2138 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2142 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2143 LOGD("linking [%s] to [%s] success",
2144 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2145 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2146 successful_link_count++;
2147 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2148 LOGD("keep audio-tee element for next audio pipeline branch");
2149 tee_element = prv_element->gst;
2152 LOGD("linking [%s] to [%s] failed",
2153 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2154 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2160 prv_element = element;
2165 return successful_link_count;
2169 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2171 GList *bucket = element_bucket;
2172 mmplayer_gst_element_t *element = NULL;
2173 int successful_add_count = 0;
2177 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2178 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2180 for (; bucket; bucket = bucket->next) {
2181 element = (mmplayer_gst_element_t *)bucket->data;
2183 if (element && element->gst) {
2184 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2185 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2186 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2187 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2190 successful_add_count++;
2196 return successful_add_count;
2200 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2202 mmplayer_t *player = (mmplayer_t *)data;
2203 GstCaps *caps = NULL;
2204 GstStructure *str = NULL;
2206 gboolean caps_ret = TRUE;
2210 MMPLAYER_RETURN_IF_FAIL(pad);
2211 MMPLAYER_RETURN_IF_FAIL(unused);
2212 MMPLAYER_RETURN_IF_FAIL(data);
2214 caps = gst_pad_get_current_caps(pad);
2218 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2222 LOGD("name = %s", name);
2224 if (strstr(name, "audio")) {
2225 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2227 if (player->audio_stream_changed_cb) {
2228 LOGE("call the audio stream changed cb");
2229 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2231 } else if (strstr(name, "video")) {
2232 if ((name = gst_structure_get_string(str, "format")))
2233 player->set_mode.video_zc = name[0] == 'S';
2235 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2236 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2238 LOGW("invalid caps info");
2243 gst_caps_unref(caps);
2251 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2256 MMPLAYER_RETURN_IF_FAIL(player);
2258 if (player->audio_stream_buff_list) {
2259 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2260 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2263 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2264 __mmplayer_audio_stream_send_data(player, tmp);
2266 MMPLAYER_FREEIF(tmp->pcm_data);
2267 MMPLAYER_FREEIF(tmp);
2270 g_list_free(player->audio_stream_buff_list);
2271 player->audio_stream_buff_list = NULL;
2278 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2280 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2283 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2285 audio_stream.bitrate = a_buffer->bitrate;
2286 audio_stream.channel = a_buffer->channel;
2287 audio_stream.depth = a_buffer->depth;
2288 audio_stream.is_little_endian = a_buffer->is_little_endian;
2289 audio_stream.channel_mask = a_buffer->channel_mask;
2290 audio_stream.data_size = a_buffer->data_size;
2291 audio_stream.data = a_buffer->pcm_data;
2292 audio_stream.pcm_format = a_buffer->pcm_format;
2294 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2296 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2302 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2304 mmplayer_t *player = (mmplayer_t *)data;
2305 const gchar *pcm_format = NULL;
2309 gint endianness = 0;
2310 guint64 channel_mask = 0;
2311 void *a_data = NULL;
2313 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2314 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2318 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2320 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2321 a_data = mapinfo.data;
2322 a_size = mapinfo.size;
2324 GstCaps *caps = gst_pad_get_current_caps(pad);
2325 GstStructure *structure = gst_caps_get_structure(caps, 0);
2327 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2329 pcm_format = gst_structure_get_string(structure, "format");
2330 gst_structure_get_int(structure, "rate", &rate);
2331 gst_structure_get_int(structure, "channels", &channel);
2332 gst_structure_get_int(structure, "depth", &depth);
2333 gst_structure_get_int(structure, "endianness", &endianness);
2334 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2335 gst_caps_unref(GST_CAPS(caps));
2337 /* In case of the sync is false, use buffer list. *
2338 * The num of buffer list depends on the num of audio channels */
2339 if (player->audio_stream_buff_list) {
2340 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2341 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2343 if (channel_mask == tmp->channel_mask) {
2345 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2347 if (tmp->data_size + a_size < tmp->buff_size) {
2348 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2349 tmp->data_size += a_size;
2351 /* send data to client */
2352 __mmplayer_audio_stream_send_data(player, tmp);
2354 if (a_size > tmp->buff_size) {
2355 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2356 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2357 if (tmp->pcm_data == NULL) {
2358 LOGE("failed to realloc data.");
2361 tmp->buff_size = a_size;
2363 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2364 memcpy(tmp->pcm_data, a_data, a_size);
2365 tmp->data_size = a_size;
2370 LOGE("data is empty in list.");
2376 /* create new audio stream data for newly found audio channel */
2377 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2378 if (a_buffer == NULL) {
2379 LOGE("failed to alloc data.");
2382 a_buffer->bitrate = rate;
2383 a_buffer->channel = channel;
2384 a_buffer->depth = depth;
2385 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2386 a_buffer->channel_mask = channel_mask;
2387 a_buffer->data_size = a_size;
2388 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2390 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2391 /* If sync is FALSE, use buffer list to reduce the IPC. */
2392 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2393 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2394 if (a_buffer->pcm_data == NULL) {
2395 LOGE("failed to alloc data.");
2396 MMPLAYER_FREEIF(a_buffer);
2399 memcpy(a_buffer->pcm_data, a_data, a_size);
2401 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2403 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2405 /* If sync is TRUE, send data directly. */
2406 a_buffer->pcm_data = a_data;
2407 __mmplayer_audio_stream_send_data(player, a_buffer);
2408 MMPLAYER_FREEIF(a_buffer);
2412 gst_buffer_unmap(buffer, &mapinfo);
2417 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2419 mmplayer_t *player = (mmplayer_t *)data;
2420 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2421 GstPad *sinkpad = NULL;
2422 GstElement *queue = NULL, *sink = NULL;
2425 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2427 queue = gst_element_factory_make("queue", NULL);
2428 if (queue == NULL) {
2429 LOGD("fail make queue");
2433 sink = gst_element_factory_make("fakesink", NULL);
2435 LOGD("fail make fakesink");
2439 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2441 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2442 LOGW("failed to link queue & sink");
2446 sinkpad = gst_element_get_static_pad(queue, "sink");
2448 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2449 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2453 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2455 gst_object_unref(sinkpad);
2456 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2457 g_object_set(sink, "sync", TRUE, NULL);
2458 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2460 /* keep the first sink reference only */
2461 if (!audiobin[MMPLAYER_A_SINK].gst) {
2462 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2463 audiobin[MMPLAYER_A_SINK].gst = sink;
2466 gst_element_set_state(sink, GST_STATE_PAUSED);
2467 gst_element_set_state(queue, GST_STATE_PAUSED);
2469 _mmplayer_add_signal_connection(player,
2471 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2473 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2476 __mmplayer_add_sink(player, sink);
2482 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2484 gst_object_unref(GST_OBJECT(queue));
2488 gst_object_unref(GST_OBJECT(sink));
2492 gst_object_unref(GST_OBJECT(sinkpad));
2500 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2502 #define MAX_PROPS_LEN 128
2503 mmplayer_gst_element_t *audiobin = NULL;
2504 gint latency_mode = 0;
2505 gchar *stream_type = NULL;
2506 gchar *latency = NULL;
2508 gchar stream_props[MAX_PROPS_LEN] = {0,};
2509 GstStructure *props = NULL;
2512 * It should be set after player creation through attribute.
2513 * But, it can not be changed during playing.
2516 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2518 audiobin = player->pipeline->audiobin;
2520 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2521 if (player->sound.mute) {
2522 LOGD("mute enabled");
2523 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2526 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2527 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2530 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2532 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2533 stream_type, stream_id, player->client_pid);
2535 props = gst_structure_from_string(stream_props, NULL);
2536 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2537 LOGI("props result[%s].", stream_props);
2538 gst_structure_free(props);
2540 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2542 switch (latency_mode) {
2543 case AUDIO_LATENCY_MODE_LOW:
2544 latency = g_strndup("low", 3);
2546 case AUDIO_LATENCY_MODE_MID:
2547 latency = g_strndup("mid", 3);
2549 case AUDIO_LATENCY_MODE_HIGH:
2550 latency = g_strndup("high", 4);
2554 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2556 LOGD("audiosink property - latency=%s", latency);
2558 MMPLAYER_FREEIF(latency);
2564 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2566 mmplayer_gst_element_t *audiobin = NULL;
2569 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2571 audiobin = player->pipeline->audiobin;
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2574 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2575 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2577 if (player->video360_yaw_radians <= M_PI &&
2578 player->video360_yaw_radians >= -M_PI &&
2579 player->video360_pitch_radians <= M_PI_2 &&
2580 player->video360_pitch_radians >= -M_PI_2) {
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2582 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2583 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2584 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2585 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2586 "source-orientation-y", player->video360_metadata.init_view_heading,
2587 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2594 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2596 mmplayer_gst_element_t *audiobin = NULL;
2597 GstPad *sink_pad = NULL;
2598 GstCaps *acaps = NULL;
2600 int pitch_control = 0;
2601 double pitch_value = 1.0;
2604 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2605 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2607 audiobin = player->pipeline->audiobin;
2609 LOGD("make element for normal audio playback");
2611 /* audio bin structure for playback. {} means optional.
2612 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2614 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2615 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2618 /* for pitch control */
2619 mm_attrs_multiple_get(player->attrs, NULL,
2620 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2621 MM_PLAYER_PITCH_VALUE, &pitch_value,
2624 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2625 if (pitch_control && (player->videodec_linked == 0)) {
2626 GstElementFactory *factory;
2628 factory = gst_element_factory_find("pitch");
2630 gst_object_unref(factory);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2637 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2639 LOGW("there is no pitch element");
2644 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2646 /* replaygain volume */
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2648 if (player->sound.rg_enable)
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2654 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2656 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2657 /* currently, only openalsink uses volume element */
2658 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2659 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2661 if (player->sound.mute) {
2662 LOGD("mute enabled");
2663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2667 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2669 /* audio effect element. if audio effect is enabled */
2670 if ((strcmp(player->ini.audioeffect_element, ""))
2672 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2675 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2677 if ((!player->bypass_audio_effect)
2678 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2679 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2680 if (!_mmplayer_audio_effect_custom_apply(player))
2681 LOGI("apply audio effect(custom) setting success");
2685 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2686 && (player->set_mode.rich_audio)) {
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2691 /* create audio sink */
2692 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2693 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2694 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2696 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2697 if (player->is_360_feature_enabled &&
2698 player->is_content_spherical &&
2700 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2701 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2702 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2704 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2709 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2711 gst_caps_unref(acaps);
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2715 player->is_openal_plugin_used = TRUE;
2717 if (player->is_360_feature_enabled && player->is_content_spherical)
2718 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2722 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2723 (player->videodec_linked && player->ini.use_system_clock)) {
2724 LOGD("system clock will be used.");
2725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2728 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2729 __mmplayer_gst_set_pulsesink_property(player);
2730 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2731 __mmplayer_gst_set_openalsink_property(player);
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2737 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2738 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2739 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2740 gst_object_unref(GST_OBJECT(sink_pad));
2742 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2745 return MM_ERROR_NONE;
2747 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2749 return MM_ERROR_PLAYER_INTERNAL;
2753 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2755 mmplayer_gst_element_t *audiobin = NULL;
2756 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2758 gchar *dst_format = NULL;
2760 int dst_samplerate = 0;
2761 int dst_channels = 0;
2762 GstCaps *caps = NULL;
2763 char *caps_str = NULL;
2766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2767 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2769 audiobin = player->pipeline->audiobin;
2771 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2773 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2775 [case 1] extract interleave audio pcm without playback
2776 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2777 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2779 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2781 [case 2] deinterleave for each channel without playback
2782 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2783 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2785 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2786 - fakesink (sync or not)
2789 [case 3] [case 1(sync only)] + playback
2790 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2792 * src - ... - tee - queue1 - playback path
2793 - queue2 - [case1 pipeline with sync]
2795 [case 4] [case 2(sync only)] + playback
2796 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2798 * src - ... - tee - queue1 - playback path
2799 - queue2 - [case2 pipeline with sync]
2803 /* 1. create tee and playback path
2804 'tee' should be added at first to copy the decoded stream
2806 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2807 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2810 /* tee - path 1 : for playback path */
2811 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2812 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2814 /* tee - path 2 : for extract path */
2815 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2816 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2819 /* if there is tee, 'tee - path 2' is linked here */
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2824 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2826 /* 2. decide the extract pcm format */
2827 mm_attrs_multiple_get(player->attrs, NULL,
2828 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2829 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2830 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2833 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2834 dst_format, dst_len, dst_samplerate, dst_channels);
2836 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2837 mm_attrs_multiple_get(player->attrs, NULL,
2838 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2839 "content_audio_samplerate", &dst_samplerate,
2840 "content_audio_channels", &dst_channels,
2843 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2844 dst_format, dst_len, dst_samplerate, dst_channels);
2846 /* If there is no enough information, set it to platform default value. */
2847 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2848 LOGD("set platform default format");
2849 dst_format = DEFAULT_PCM_OUT_FORMAT;
2851 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2852 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2855 /* 3. create capsfilter */
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2857 caps = gst_caps_new_simple("audio/x-raw",
2858 "format", G_TYPE_STRING, dst_format,
2859 "rate", G_TYPE_INT, dst_samplerate,
2860 "channels", G_TYPE_INT, dst_channels,
2863 caps_str = gst_caps_to_string(caps);
2864 LOGD("new caps : %s", caps_str);
2866 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2869 gst_caps_unref(caps);
2870 MMPLAYER_FREEIF(caps_str);
2872 /* 4-1. create deinterleave to extract pcm for each channel */
2873 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2874 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2875 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2877 /* audiosink will be added after getting signal for each channel */
2878 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2881 /* 4-2. create fakesink to extract interlevaed pcm */
2882 LOGD("add audio fakesink for interleaved audio");
2883 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2884 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2885 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2888 _mmplayer_add_signal_connection(player,
2889 G_OBJECT(audiobin[extract_sink_id].gst),
2890 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2892 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2895 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2899 return MM_ERROR_NONE;
2901 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2903 return MM_ERROR_PLAYER_INTERNAL;
2907 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2909 int ret = MM_ERROR_NONE;
2910 mmplayer_gst_element_t *audiobin = NULL;
2911 GList *element_bucket = NULL;
2914 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2915 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917 audiobin = player->pipeline->audiobin;
2919 if (player->build_audio_offload) { /* skip all the audio filters */
2920 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2922 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2923 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2924 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2926 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2930 /* FIXME: need to mention the supportable condition at API reference */
2931 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2932 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2934 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2936 if (ret != MM_ERROR_NONE)
2939 LOGD("success to make audio bin element");
2940 *bucket = element_bucket;
2943 return MM_ERROR_NONE;
2946 LOGE("failed to make audio bin element");
2947 g_list_free(element_bucket);
2951 return MM_ERROR_PLAYER_INTERNAL;
2955 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2957 mmplayer_gst_element_t *first_element = NULL;
2958 mmplayer_gst_element_t *audiobin = NULL;
2960 GstPad *ghostpad = NULL;
2961 GList *element_bucket = NULL;
2965 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2968 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2970 LOGE("failed to allocate memory for audiobin");
2971 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2975 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2976 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2977 if (!audiobin[MMPLAYER_A_BIN].gst) {
2978 LOGE("failed to create audiobin");
2983 player->pipeline->audiobin = audiobin;
2985 /* create audio filters and audiosink */
2986 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2989 /* adding created elements to bin */
2990 LOGD("adding created elements to bin");
2991 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2994 /* linking elements in the bucket by added order. */
2995 LOGD("Linking elements in the bucket by added order.");
2996 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
2999 /* get first element's sinkpad for creating ghostpad */
3000 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3001 if (!first_element) {
3002 LOGE("failed to get first elem");
3006 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3008 LOGE("failed to get pad from first element of audiobin");
3012 ghostpad = gst_ghost_pad_new("sink", pad);
3014 LOGE("failed to create ghostpad");
3018 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3019 LOGE("failed to add ghostpad to audiobin");
3023 gst_object_unref(pad);
3025 g_list_free(element_bucket);
3028 return MM_ERROR_NONE;
3031 LOGD("ERROR : releasing audiobin");
3034 gst_object_unref(GST_OBJECT(pad));
3037 gst_object_unref(GST_OBJECT(ghostpad));
3040 g_list_free(element_bucket);
3042 /* release element which are not added to bin */
3043 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3044 /* NOTE : skip bin */
3045 if (audiobin[i].gst) {
3046 GstObject *parent = NULL;
3047 parent = gst_element_get_parent(audiobin[i].gst);
3050 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3051 audiobin[i].gst = NULL;
3053 gst_object_unref(GST_OBJECT(parent));
3057 /* release audiobin with it's childs */
3058 if (audiobin[MMPLAYER_A_BIN].gst)
3059 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3061 MMPLAYER_FREEIF(audiobin);
3063 player->pipeline->audiobin = NULL;
3065 return MM_ERROR_PLAYER_INTERNAL;
3069 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3071 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3075 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3077 int ret = MM_ERROR_NONE;
3079 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3080 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3082 MMPLAYER_VIDEO_BO_LOCK(player);
3084 if (player->video_bo_list) {
3085 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3086 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3087 if (tmp && tmp->bo == bo) {
3089 LOGD("release bo %p", bo);
3090 tbm_bo_unref(tmp->bo);
3091 MMPLAYER_VIDEO_BO_UNLOCK(player);
3092 MMPLAYER_VIDEO_BO_SIGNAL(player);
3097 /* hw codec is running or the list was reset for DRC. */
3098 LOGW("there is no bo list.");
3100 MMPLAYER_VIDEO_BO_UNLOCK(player);
3102 LOGW("failed to find bo %p", bo);
3107 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3112 MMPLAYER_RETURN_IF_FAIL(player);
3114 MMPLAYER_VIDEO_BO_LOCK(player);
3115 if (player->video_bo_list) {
3116 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3117 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3118 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3121 tbm_bo_unref(tmp->bo);
3125 g_list_free(player->video_bo_list);
3126 player->video_bo_list = NULL;
3128 player->video_bo_size = 0;
3129 MMPLAYER_VIDEO_BO_UNLOCK(player);
3136 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3139 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3140 gboolean ret = TRUE;
3142 /* check DRC, if it is, destroy the prev bo list to create again */
3143 if (player->video_bo_size != size) {
3144 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3145 __mmplayer_video_stream_destroy_bo_list(player);
3146 player->video_bo_size = size;
3149 MMPLAYER_VIDEO_BO_LOCK(player);
3151 if ((!player->video_bo_list) ||
3152 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3154 /* create bo list */
3156 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3158 if (player->video_bo_list) {
3159 /* if bo list did not created all, try it again. */
3160 idx = g_list_length(player->video_bo_list);
3161 LOGD("bo list exist(len: %d)", idx);
3164 for (; idx < player->ini.num_of_video_bo; idx++) {
3165 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3167 LOGE("Fail to alloc bo_info.");
3170 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3172 LOGE("Fail to tbm_bo_alloc.");
3173 MMPLAYER_FREEIF(bo_info);
3176 bo_info->used = FALSE;
3177 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3180 /* update video num buffers */
3181 LOGD("video_num_buffers : %d", idx);
3182 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3183 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3186 MMPLAYER_VIDEO_BO_UNLOCK(player);
3192 /* get bo from list*/
3193 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3194 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3195 if (tmp && (tmp->used == FALSE)) {
3196 LOGD("found bo %p to use", tmp->bo);
3198 MMPLAYER_VIDEO_BO_UNLOCK(player);
3199 return tbm_bo_ref(tmp->bo);
3203 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3204 MMPLAYER_VIDEO_BO_UNLOCK(player);
3208 if (player->ini.video_bo_timeout <= 0) {
3209 MMPLAYER_VIDEO_BO_WAIT(player);
3211 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3212 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3219 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3221 mmplayer_t *player = (mmplayer_t *)data;
3223 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3225 /* send prerolled pkt */
3226 player->video_stream_prerolled = false;
3228 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3230 /* not to send prerolled pkt again */
3231 player->video_stream_prerolled = true;
3235 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3237 mmplayer_t *player = (mmplayer_t *)data;
3238 mmplayer_video_decoded_data_info_t *stream = NULL;
3239 GstMemory *mem = NULL;
3242 MMPLAYER_RETURN_IF_FAIL(player);
3243 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3245 if (player->video_stream_prerolled) {
3246 player->video_stream_prerolled = false;
3247 LOGD("skip the prerolled pkt not to send it again");
3251 /* clear stream data structure */
3252 stream = __mmplayer_create_stream_from_pad(pad);
3254 LOGE("failed to alloc stream");
3258 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3260 /* set size and timestamp */
3261 mem = gst_buffer_peek_memory(buffer, 0);
3262 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3263 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3265 /* check zero-copy */
3266 if (player->set_mode.video_zc &&
3267 player->set_mode.video_export &&
3268 gst_is_tizen_memory(mem)) {
3269 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3270 stream->internal_buffer = gst_buffer_ref(buffer);
3271 } else { /* sw codec */
3272 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3275 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3279 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3280 LOGE("failed to send video decoded data.");
3287 LOGE("release video stream resource.");
3288 if (gst_is_tizen_memory(mem)) {
3290 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3292 tbm_bo_unref(stream->bo[i]);
3295 /* unref gst buffer */
3296 if (stream->internal_buffer)
3297 gst_buffer_unref(stream->internal_buffer);
3300 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3302 MMPLAYER_FREEIF(stream);
3307 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3309 mmplayer_gst_element_t *videobin = NULL;
3312 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3314 videobin = player->pipeline->videobin;
3316 /* Set spatial media metadata and/or user settings to the element.
3318 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3319 "projection-type", player->video360_metadata.projection_type, NULL);
3321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3322 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3324 if (player->video360_metadata.full_pano_width_pixels &&
3325 player->video360_metadata.full_pano_height_pixels &&
3326 player->video360_metadata.cropped_area_image_width &&
3327 player->video360_metadata.cropped_area_image_height) {
3328 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3329 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3330 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3331 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3332 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3333 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3334 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3338 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3339 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3340 "horizontal-fov", player->video360_horizontal_fov,
3341 "vertical-fov", player->video360_vertical_fov, NULL);
3344 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3345 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3346 "zoom", 1.0f / player->video360_zoom, NULL);
3349 if (player->video360_yaw_radians <= M_PI &&
3350 player->video360_yaw_radians >= -M_PI &&
3351 player->video360_pitch_radians <= M_PI_2 &&
3352 player->video360_pitch_radians >= -M_PI_2) {
3353 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3354 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3355 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3356 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3357 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3358 "pose-yaw", player->video360_metadata.init_view_heading,
3359 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3362 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3363 "passthrough", !player->is_video360_enabled, NULL);
3370 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3372 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3373 GList *element_bucket = NULL;
3376 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3378 /* create video360 filter */
3379 if (player->is_360_feature_enabled && player->is_content_spherical) {
3380 LOGD("create video360 element");
3381 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3382 __mmplayer_gst_set_video360_property(player);
3386 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3387 LOGD("skip creating the videoconv and rotator");
3388 return MM_ERROR_NONE;
3391 /* in case of sw codec & overlay surface type, except 360 playback.
3392 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3393 LOGD("create video converter: %s", video_csc);
3394 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3397 *bucket = element_bucket;
3399 return MM_ERROR_NONE;
3401 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3402 g_list_free(element_bucket);
3406 return MM_ERROR_PLAYER_INTERNAL;
3410 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3412 gchar *factory_name = NULL;
3414 switch (surface_type) {
3415 case MM_DISPLAY_SURFACE_OVERLAY:
3416 if (strlen(player->ini.videosink_element_overlay) > 0)
3417 factory_name = player->ini.videosink_element_overlay;
3419 case MM_DISPLAY_SURFACE_REMOTE:
3420 case MM_DISPLAY_SURFACE_NULL:
3421 if (strlen(player->ini.videosink_element_fake) > 0)
3422 factory_name = player->ini.videosink_element_fake;
3425 LOGE("unidentified surface type");
3429 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3430 return factory_name;
3434 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3436 gchar *factory_name = NULL;
3437 mmplayer_gst_element_t *videobin = NULL;
3442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3444 videobin = player->pipeline->videobin;
3445 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3447 attrs = MMPLAYER_GET_ATTRS(player);
3449 LOGE("cannot get content attribute");
3450 return MM_ERROR_PLAYER_INTERNAL;
3453 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3454 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3455 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3457 /* support shard memory with S/W codec on HawkP */
3458 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3459 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3460 "use-tbm", use_tbm, NULL);
3464 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3465 return MM_ERROR_PLAYER_INTERNAL;
3467 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3468 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3471 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3473 LOGD("disable last-sample");
3474 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3477 if (player->set_mode.video_export) {
3479 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3480 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3481 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3483 _mmplayer_add_signal_connection(player,
3484 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3485 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3487 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3490 _mmplayer_add_signal_connection(player,
3491 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3492 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3494 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3498 if (videobin[MMPLAYER_V_SINK].gst) {
3499 GstPad *sink_pad = NULL;
3500 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3502 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3503 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3504 gst_object_unref(GST_OBJECT(sink_pad));
3506 LOGE("failed to get sink pad from videosink");
3510 return MM_ERROR_NONE;
3515 * - video overlay surface(arm/x86) : tizenwlsink
3518 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3521 GList *element_bucket = NULL;
3522 mmplayer_gst_element_t *first_element = NULL;
3523 mmplayer_gst_element_t *videobin = NULL;
3524 gchar *videosink_factory_name = NULL;
3527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3530 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3532 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3534 player->pipeline->videobin = videobin;
3537 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3538 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3539 if (!videobin[MMPLAYER_V_BIN].gst) {
3540 LOGE("failed to create videobin");
3544 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3547 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3548 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3550 /* additional setting for sink plug-in */
3551 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3552 LOGE("failed to set video property");
3556 /* store it as it's sink element */
3557 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3559 /* adding created elements to bin */
3560 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3561 LOGE("failed to add elements");
3565 /* Linking elements in the bucket by added order */
3566 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3567 LOGE("failed to link elements");
3571 /* get first element's sinkpad for creating ghostpad */
3572 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3573 if (!first_element) {
3574 LOGE("failed to get first element from bucket");
3578 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3580 LOGE("failed to get pad from first element");
3584 /* create ghostpad */
3585 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3586 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3587 LOGE("failed to add ghostpad to videobin");
3590 gst_object_unref(pad);
3592 /* done. free allocated variables */
3593 g_list_free(element_bucket);
3597 return MM_ERROR_NONE;
3600 LOGE("ERROR : releasing videobin");
3601 g_list_free(element_bucket);
3604 gst_object_unref(GST_OBJECT(pad));
3606 /* release videobin with it's childs */
3607 if (videobin[MMPLAYER_V_BIN].gst)
3608 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3610 MMPLAYER_FREEIF(videobin);
3611 player->pipeline->videobin = NULL;
3613 return MM_ERROR_PLAYER_INTERNAL;
3617 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3619 GList *element_bucket = NULL;
3620 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3622 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3623 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3624 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3625 "signal-handoffs", FALSE,
3628 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3629 _mmplayer_add_signal_connection(player,
3630 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3631 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3633 G_CALLBACK(__mmplayer_update_subtitle),
3636 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3637 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3639 if (!player->play_subtitle) {
3640 LOGD("add textbin sink as sink element of whole pipeline.");
3641 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3644 /* adding created elements to bin */
3645 LOGD("adding created elements to bin");
3646 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3647 LOGE("failed to add elements");
3651 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3652 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3653 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3655 /* linking elements in the bucket by added order. */
3656 LOGD("Linking elements in the bucket by added order.");
3657 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3658 LOGE("failed to link elements");
3662 /* done. free allocated variables */
3663 g_list_free(element_bucket);
3665 if (textbin[MMPLAYER_T_QUEUE].gst) {
3667 GstPad *ghostpad = NULL;
3669 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3671 LOGE("failed to get sink pad of text queue");
3675 ghostpad = gst_ghost_pad_new("text_sink", pad);
3676 gst_object_unref(pad);
3679 LOGE("failed to create ghostpad of textbin");
3683 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3684 LOGE("failed to add ghostpad to textbin");
3685 gst_object_unref(ghostpad);
3690 return MM_ERROR_NONE;
3693 g_list_free(element_bucket);
3695 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3696 LOGE("remove textbin sink from sink list");
3697 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3700 /* release element at __mmplayer_gst_create_text_sink_bin */
3701 return MM_ERROR_PLAYER_INTERNAL;
3705 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3707 mmplayer_gst_element_t *textbin = NULL;
3708 GList *element_bucket = NULL;
3709 int surface_type = 0;
3714 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3717 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3719 LOGE("failed to allocate memory for textbin");
3720 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3724 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3725 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3726 if (!textbin[MMPLAYER_T_BIN].gst) {
3727 LOGE("failed to create textbin");
3732 player->pipeline->textbin = textbin;
3735 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3736 LOGD("surface type for subtitle : %d", surface_type);
3737 switch (surface_type) {
3738 case MM_DISPLAY_SURFACE_OVERLAY:
3739 case MM_DISPLAY_SURFACE_NULL:
3740 case MM_DISPLAY_SURFACE_REMOTE:
3741 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3742 LOGE("failed to make plain text elements");
3753 return MM_ERROR_NONE;
3757 LOGD("ERROR : releasing textbin");
3759 g_list_free(element_bucket);
3761 /* release signal */
3762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3764 /* release element which are not added to bin */
3765 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3766 /* NOTE : skip bin */
3767 if (textbin[i].gst) {
3768 GstObject *parent = NULL;
3769 parent = gst_element_get_parent(textbin[i].gst);
3772 gst_object_unref(GST_OBJECT(textbin[i].gst));
3773 textbin[i].gst = NULL;
3775 gst_object_unref(GST_OBJECT(parent));
3780 /* release textbin with it's childs */
3781 if (textbin[MMPLAYER_T_BIN].gst)
3782 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3784 MMPLAYER_FREEIF(player->pipeline->textbin);
3785 player->pipeline->textbin = NULL;
3788 return MM_ERROR_PLAYER_INTERNAL;
3792 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3794 mmplayer_gst_element_t *mainbin = NULL;
3795 mmplayer_gst_element_t *textbin = NULL;
3796 MMHandleType attrs = 0;
3797 GstElement *subsrc = NULL;
3798 GstElement *subparse = NULL;
3799 gchar *subtitle_uri = NULL;
3800 const gchar *charset = NULL;
3806 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3808 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3810 mainbin = player->pipeline->mainbin;
3812 attrs = MMPLAYER_GET_ATTRS(player);
3814 LOGE("cannot get content attribute");
3815 return MM_ERROR_PLAYER_INTERNAL;
3818 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3819 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3820 LOGE("subtitle uri is not proper filepath.");
3821 return MM_ERROR_PLAYER_INVALID_URI;
3824 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3825 LOGE("failed to get storage info of subtitle path");
3826 return MM_ERROR_PLAYER_INVALID_URI;
3829 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3831 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3832 player->subtitle_language_list = NULL;
3833 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3835 /* create the subtitle source */
3836 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3838 LOGE("failed to create filesrc element");
3841 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3843 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3844 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3846 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3847 LOGW("failed to add queue");
3848 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3849 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3850 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3855 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3857 LOGE("failed to create subparse element");
3861 charset = _mmplayer_get_charset(subtitle_uri);
3863 LOGD("detected charset is %s", charset);
3864 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3867 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3868 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3870 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3871 LOGW("failed to add subparse");
3872 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3873 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3874 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3878 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3879 LOGW("failed to link subsrc and subparse");
3883 player->play_subtitle = TRUE;
3884 player->adjust_subtitle_pos = 0;
3886 LOGD("play subtitle using subtitle file");
3888 if (player->pipeline->textbin == NULL) {
3889 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3890 LOGE("failed to create text sink bin. continuing without text");
3894 textbin = player->pipeline->textbin;
3896 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3897 LOGW("failed to add textbin");
3899 /* release signal */
3900 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3902 /* release textbin with it's childs */
3903 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3904 MMPLAYER_FREEIF(player->pipeline->textbin);
3905 player->pipeline->textbin = textbin = NULL;
3909 LOGD("link text input selector and textbin ghost pad");
3911 player->textsink_linked = 1;
3912 player->external_text_idx = 0;
3913 LOGI("textsink is linked");
3915 textbin = player->pipeline->textbin;
3916 LOGD("text bin has been created. reuse it.");
3917 player->external_text_idx = 1;
3920 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3921 LOGW("failed to link subparse and textbin");
3925 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3927 LOGE("failed to get sink pad from textsink to probe data");
3931 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3932 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3934 gst_object_unref(pad);
3937 /* create dot. for debugging */
3938 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3941 return MM_ERROR_NONE;
3944 /* release text pipeline resource */
3945 player->textsink_linked = 0;
3947 /* release signal */
3948 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3950 if (player->pipeline->textbin) {
3951 LOGE("remove textbin");
3953 /* release textbin with it's childs */
3954 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3955 MMPLAYER_FREEIF(player->pipeline->textbin);
3956 player->pipeline->textbin = NULL;
3960 /* release subtitle elem */
3961 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3962 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3964 return MM_ERROR_PLAYER_INTERNAL;
3968 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3970 mmplayer_t *player = (mmplayer_t *)data;
3971 MMMessageParamType msg = {0, };
3972 GstClockTime duration = 0;
3973 gpointer text = NULL;
3974 guint text_size = 0;
3975 gboolean ret = TRUE;
3976 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3980 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3981 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3983 if (player->is_subtitle_force_drop) {
3984 LOGW("subtitle is dropped forcedly.");
3988 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3989 text = mapinfo.data;
3990 text_size = mapinfo.size;
3992 if (player->set_mode.subtitle_off) {
3993 LOGD("subtitle is OFF.");
3997 if (!text || (text_size == 0)) {
3998 LOGD("There is no subtitle to be displayed.");
4002 msg.data = (void *)text;
4004 duration = GST_BUFFER_DURATION(buffer);
4006 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4007 if (player->duration > GST_BUFFER_PTS(buffer))
4008 duration = player->duration - GST_BUFFER_PTS(buffer);
4011 LOGI("subtitle duration is invalid, subtitle duration change "
4012 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4014 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4016 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4018 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4019 gst_buffer_unmap(buffer, &mapinfo);
4026 static GstPadProbeReturn
4027 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4029 mmplayer_t *player = (mmplayer_t *)u_data;
4030 GstClockTime cur_timestamp = 0;
4031 gint64 adjusted_timestamp = 0;
4032 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4034 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4036 if (player->set_mode.subtitle_off) {
4037 LOGD("subtitle is OFF.");
4041 if (player->adjust_subtitle_pos == 0) {
4042 LOGD("nothing to do");
4046 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4047 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4049 if (adjusted_timestamp < 0) {
4050 LOGD("adjusted_timestamp under zero");
4055 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4056 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4057 GST_TIME_ARGS(cur_timestamp),
4058 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4060 return GST_PAD_PROBE_OK;
4064 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4068 /* check player and subtitlebin are created */
4069 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4070 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4072 if (position == 0) {
4073 LOGD("nothing to do");
4075 return MM_ERROR_NONE;
4078 /* check current postion */
4079 player->adjust_subtitle_pos = position;
4081 LOGD("save adjust_subtitle_pos in player");
4085 return MM_ERROR_NONE;
4089 * This function is to create audio or video pipeline for playing.
4091 * @param player [in] handle of player
4093 * @return This function returns zero on success.
4098 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4100 int ret = MM_ERROR_NONE;
4101 mmplayer_gst_element_t *mainbin = NULL;
4102 MMHandleType attrs = 0;
4105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4107 /* get profile attribute */
4108 attrs = MMPLAYER_GET_ATTRS(player);
4110 LOGE("failed to get content attribute");
4114 /* create pipeline handles */
4115 if (player->pipeline) {
4116 LOGE("pipeline should be released before create new one");
4120 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4121 if (player->pipeline == NULL)
4124 /* create mainbin */
4125 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4126 if (mainbin == NULL)
4129 /* create pipeline */
4130 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4131 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4132 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4133 LOGE("failed to create pipeline");
4138 player->pipeline->mainbin = mainbin;
4140 /* create the source and decoder elements */
4141 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4142 ret = _mmplayer_gst_build_es_pipeline(player);
4144 ret = _mmplayer_gst_build_pipeline(player);
4146 if (ret != MM_ERROR_NONE) {
4147 LOGE("failed to create some elements");
4151 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4152 if (__mmplayer_check_subtitle(player)
4153 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4154 LOGE("failed to create text pipeline");
4157 ret = _mmplayer_gst_add_bus_watch(player);
4158 if (ret != MM_ERROR_NONE) {
4159 LOGE("failed to add bus watch");
4164 return MM_ERROR_NONE;
4167 __mmplayer_gst_destroy_pipeline(player);
4168 return MM_ERROR_PLAYER_INTERNAL;
4172 __mmplayer_reset_gapless_state(mmplayer_t *player)
4175 MMPLAYER_RETURN_IF_FAIL(player
4177 && player->pipeline->audiobin
4178 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4180 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4187 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4190 int ret = MM_ERROR_NONE;
4194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4196 /* cleanup stuffs */
4197 MMPLAYER_FREEIF(player->type);
4198 player->no_more_pad = FALSE;
4199 player->num_dynamic_pad = 0;
4200 player->demux_pad_index = 0;
4202 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4203 player->subtitle_language_list = NULL;
4204 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4206 __mmplayer_reset_gapless_state(player);
4208 if (player->streamer) {
4209 _mm_player_streaming_initialize(player->streamer, FALSE);
4210 _mm_player_streaming_destroy(player->streamer);
4211 player->streamer = NULL;
4214 /* cleanup unlinked mime type */
4215 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4216 MMPLAYER_FREEIF(player->unlinked_video_mime);
4217 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4219 /* cleanup running stuffs */
4220 _mmplayer_cancel_eos_timer(player);
4222 /* cleanup gst stuffs */
4223 if (player->pipeline) {
4224 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4225 GstTagList *tag_list = player->pipeline->tag_list;
4227 /* first we need to disconnect all signal hander */
4228 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4231 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4232 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4233 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4234 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4235 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4236 gst_object_unref(bus);
4238 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4239 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4240 if (ret != MM_ERROR_NONE) {
4241 LOGE("fail to change state to NULL");
4242 return MM_ERROR_PLAYER_INTERNAL;
4245 LOGW("succeeded in changing state to NULL");
4247 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4250 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4251 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4253 /* free avsysaudiosink
4254 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4255 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4257 MMPLAYER_FREEIF(audiobin);
4258 MMPLAYER_FREEIF(videobin);
4259 MMPLAYER_FREEIF(textbin);
4260 MMPLAYER_FREEIF(mainbin);
4264 gst_tag_list_unref(tag_list);
4266 MMPLAYER_FREEIF(player->pipeline);
4268 MMPLAYER_FREEIF(player->album_art);
4270 if (player->v_stream_caps) {
4271 gst_caps_unref(player->v_stream_caps);
4272 player->v_stream_caps = NULL;
4275 if (player->a_stream_caps) {
4276 gst_caps_unref(player->a_stream_caps);
4277 player->a_stream_caps = NULL;
4280 if (player->s_stream_caps) {
4281 gst_caps_unref(player->s_stream_caps);
4282 player->s_stream_caps = NULL;
4284 _mmplayer_track_destroy(player);
4286 if (player->sink_elements)
4287 g_list_free(player->sink_elements);
4288 player->sink_elements = NULL;
4290 if (player->bufmgr) {
4291 tbm_bufmgr_deinit(player->bufmgr);
4292 player->bufmgr = NULL;
4295 LOGW("finished destroy pipeline");
4303 __mmplayer_gst_realize(mmplayer_t *player)
4306 int ret = MM_ERROR_NONE;
4310 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4312 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4314 ret = __mmplayer_gst_create_pipeline(player);
4316 LOGE("failed to create pipeline");
4320 /* set pipeline state to READY */
4321 /* NOTE : state change to READY must be performed sync. */
4322 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4323 ret = _mmplayer_gst_set_state(player,
4324 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4326 if (ret != MM_ERROR_NONE) {
4327 /* return error if failed to set state */
4328 LOGE("failed to set READY state");
4332 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4334 /* create dot before error-return. for debugging */
4335 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4343 __mmplayer_gst_unrealize(mmplayer_t *player)
4345 int ret = MM_ERROR_NONE;
4349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4351 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4352 MMPLAYER_PRINT_STATE(player);
4354 /* release miscellaneous information */
4355 __mmplayer_release_misc(player);
4357 /* destroy pipeline */
4358 ret = __mmplayer_gst_destroy_pipeline(player);
4359 if (ret != MM_ERROR_NONE) {
4360 LOGE("failed to destory pipeline");
4364 /* release miscellaneous information.
4365 these info needs to be released after pipeline is destroyed. */
4366 __mmplayer_release_misc_post(player);
4368 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4376 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4381 LOGW("set_message_callback is called with invalid player handle");
4382 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4385 player->msg_cb = callback;
4386 player->msg_cb_param = user_param;
4388 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4392 return MM_ERROR_NONE;
4396 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4398 int ret = MM_ERROR_NONE;
4403 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4404 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4405 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4407 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4409 if (strstr(uri, "es_buff://")) {
4410 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4411 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4412 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4413 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4415 tmp = g_ascii_strdown(uri, strlen(uri));
4416 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4417 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4419 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4421 } else if (strstr(uri, "mms://")) {
4422 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4423 } else if ((path = strstr(uri, "mem://"))) {
4424 ret = __mmplayer_set_mem_uri(data, path, param);
4426 ret = __mmplayer_set_file_uri(data, uri);
4429 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4430 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4431 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4432 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4434 /* dump parse result */
4435 SECURE_LOGW("incoming uri : %s", uri);
4436 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4437 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4445 __mmplayer_can_do_interrupt(mmplayer_t *player)
4447 if (!player || !player->pipeline || !player->attrs) {
4448 LOGW("not initialized");
4452 if (player->audio_decoded_cb) {
4453 LOGW("not support in pcm extraction mode");
4457 /* check if seeking */
4458 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4459 MMMessageParamType msg_param;
4460 memset(&msg_param, 0, sizeof(MMMessageParamType));
4461 msg_param.code = MM_ERROR_PLAYER_SEEK;
4462 player->seek_state = MMPLAYER_SEEK_NONE;
4463 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4467 /* check other thread */
4468 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4469 LOGW("locked already, cmd state : %d", player->cmd);
4471 /* check application command */
4472 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4473 LOGW("playing.. should wait cmd lock then, will be interrupted");
4475 /* lock will be released at mrp_resource_release_cb() */
4476 MMPLAYER_CMD_LOCK(player);
4479 LOGW("nothing to do");
4482 LOGW("can interrupt immediately");
4486 FAILED: /* with CMD UNLOCKED */
4489 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4494 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4497 mmplayer_t *player = NULL;
4498 MMMessageParamType msg = {0, };
4500 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4505 LOGE("user_data is null");
4508 player = (mmplayer_t *)user_data;
4510 if (!__mmplayer_can_do_interrupt(player)) {
4511 LOGW("no need to interrupt, so leave");
4512 /* FIXME: there is no way to avoid releasing resource. */
4516 player->interrupted_by_resource = TRUE;
4518 /* get last play position */
4519 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4520 msg.union_type = MM_MSG_UNION_TIME;
4521 msg.time.elapsed = pos;
4522 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4524 LOGW("failed to get play position.");
4527 LOGD("video resource conflict so, resource will be freed by unrealizing");
4528 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4529 LOGE("failed to unrealize");
4531 /* lock is called in __mmplayer_can_do_interrupt() */
4532 MMPLAYER_CMD_UNLOCK(player);
4534 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4535 player->hw_resource[res_idx] = NULL;
4539 return TRUE; /* release all the resources */
4543 __mmplayer_initialize_video_roi(mmplayer_t *player)
4545 player->video_roi.scale_x = 0.0;
4546 player->video_roi.scale_y = 0.0;
4547 player->video_roi.scale_width = 1.0;
4548 player->video_roi.scale_height = 1.0;
4552 _mmplayer_create_player(MMHandleType handle)
4554 int ret = MM_ERROR_PLAYER_INTERNAL;
4555 bool enabled = false;
4557 mmplayer_t *player = MM_PLAYER_CAST(handle);
4561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4563 /* initialize player state */
4564 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4565 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4566 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4567 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4569 /* check current state */
4570 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4572 /* construct attributes */
4573 player->attrs = _mmplayer_construct_attribute(handle);
4575 if (!player->attrs) {
4576 LOGE("Failed to construct attributes");
4580 /* initialize gstreamer with configured parameter */
4581 if (!__mmplayer_init_gstreamer(player)) {
4582 LOGE("Initializing gstreamer failed");
4583 _mmplayer_deconstruct_attribute(handle);
4587 /* create lock. note that g_tread_init() has already called in gst_init() */
4588 g_mutex_init(&player->fsink_lock);
4590 /* create update tag lock */
4591 g_mutex_init(&player->update_tag_lock);
4593 /* create gapless play mutex */
4594 g_mutex_init(&player->gapless_play_thread_mutex);
4596 /* create gapless play cond */
4597 g_cond_init(&player->gapless_play_thread_cond);
4599 /* create gapless play thread */
4600 player->gapless_play_thread =
4601 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4602 if (!player->gapless_play_thread) {
4603 LOGE("failed to create gapless play thread");
4604 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4605 g_mutex_clear(&player->gapless_play_thread_mutex);
4606 g_cond_clear(&player->gapless_play_thread_cond);
4610 player->bus_msg_q = g_queue_new();
4611 if (!player->bus_msg_q) {
4612 LOGE("failed to create queue for bus_msg");
4613 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4617 ret = _mmplayer_initialize_video_capture(player);
4618 if (ret != MM_ERROR_NONE) {
4619 LOGE("failed to initialize video capture");
4623 /* initialize resource manager */
4624 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4625 __resource_release_cb, player, &player->resource_manager)
4626 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4627 LOGE("failed to initialize resource manager");
4628 ret = MM_ERROR_PLAYER_INTERNAL;
4632 /* create video bo lock and cond */
4633 g_mutex_init(&player->video_bo_mutex);
4634 g_cond_init(&player->video_bo_cond);
4636 /* create subtitle info lock and cond */
4637 g_mutex_init(&player->subtitle_info_mutex);
4638 g_cond_init(&player->subtitle_info_cond);
4640 player->streaming_type = STREAMING_SERVICE_NONE;
4642 /* give default value of audio effect setting */
4643 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4644 player->sound.rg_enable = false;
4645 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4647 player->play_subtitle = FALSE;
4648 player->has_closed_caption = FALSE;
4649 player->pending_resume = FALSE;
4650 if (player->ini.dump_element_keyword[0][0] == '\0')
4651 player->ini.set_dump_element_flag = FALSE;
4653 player->ini.set_dump_element_flag = TRUE;
4655 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4656 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4657 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4659 /* Set video360 settings to their defaults for just-created player.
4662 player->is_360_feature_enabled = FALSE;
4663 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4664 LOGI("spherical feature info: %d", enabled);
4666 player->is_360_feature_enabled = TRUE;
4668 LOGE("failed to get spherical feature info");
4671 player->is_content_spherical = FALSE;
4672 player->is_video360_enabled = TRUE;
4673 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4674 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4675 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4676 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4677 player->video360_zoom = 1.0f;
4678 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4679 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4681 __mmplayer_initialize_video_roi(player);
4683 /* set player state to null */
4684 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4685 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4689 return MM_ERROR_NONE;
4693 g_mutex_clear(&player->fsink_lock);
4694 /* free update tag lock */
4695 g_mutex_clear(&player->update_tag_lock);
4696 g_queue_free(player->bus_msg_q);
4697 player->bus_msg_q = NULL;
4698 /* free gapless play thread */
4699 if (player->gapless_play_thread) {
4700 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4701 player->gapless_play_thread_exit = TRUE;
4702 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4703 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4705 g_thread_join(player->gapless_play_thread);
4706 player->gapless_play_thread = NULL;
4708 g_mutex_clear(&player->gapless_play_thread_mutex);
4709 g_cond_clear(&player->gapless_play_thread_cond);
4712 /* release attributes */
4713 _mmplayer_deconstruct_attribute(handle);
4721 __mmplayer_init_gstreamer(mmplayer_t *player)
4723 static gboolean initialized = FALSE;
4724 static const int max_argc = 50;
4726 gchar **argv = NULL;
4727 gchar **argv2 = NULL;
4733 LOGD("gstreamer already initialized.");
4738 argc = malloc(sizeof(int));
4739 argv = malloc(sizeof(gchar *) * max_argc);
4740 argv2 = malloc(sizeof(gchar *) * max_argc);
4742 if (!argc || !argv || !argv2)
4745 memset(argv, 0, sizeof(gchar *) * max_argc);
4746 memset(argv2, 0, sizeof(gchar *) * max_argc);
4750 argv[0] = g_strdup("mmplayer");
4753 for (i = 0; i < 5; i++) {
4754 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4755 if (strlen(player->ini.gst_param[i]) > 0) {
4756 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4761 /* we would not do fork for scanning plugins */
4762 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4765 /* check disable registry scan */
4766 if (player->ini.skip_rescan) {
4767 argv[*argc] = g_strdup("--gst-disable-registry-update");
4771 /* check disable segtrap */
4772 if (player->ini.disable_segtrap) {
4773 argv[*argc] = g_strdup("--gst-disable-segtrap");
4777 LOGD("initializing gstreamer with following parameter");
4778 LOGD("argc : %d", *argc);
4781 for (i = 0; i < arg_count; i++) {
4783 LOGD("argv[%d] : %s", i, argv2[i]);
4786 /* initializing gstreamer */
4787 if (!gst_init_check(argc, &argv, &err)) {
4788 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4795 for (i = 0; i < arg_count; i++) {
4797 LOGD("release - argv[%d] : %s", i, argv2[i]);
4799 MMPLAYER_FREEIF(argv2[i]);
4802 MMPLAYER_FREEIF(argv);
4803 MMPLAYER_FREEIF(argv2);
4804 MMPLAYER_FREEIF(argc);
4814 for (i = 0; i < arg_count; i++) {
4815 LOGD("free[%d] : %s", i, argv2[i]);
4816 MMPLAYER_FREEIF(argv2[i]);
4819 MMPLAYER_FREEIF(argv);
4820 MMPLAYER_FREEIF(argv2);
4821 MMPLAYER_FREEIF(argc);
4827 __mmplayer_check_async_state_transition(mmplayer_t *player)
4829 GstState element_state = GST_STATE_VOID_PENDING;
4830 GstState element_pending_state = GST_STATE_VOID_PENDING;
4831 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4832 GstElement *element = NULL;
4833 gboolean async = FALSE;
4835 /* check player handle */
4836 MMPLAYER_RETURN_IF_FAIL(player &&
4838 player->pipeline->mainbin &&
4839 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4842 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4844 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4845 LOGD("don't need to check the pipeline state");
4849 MMPLAYER_PRINT_STATE(player);
4851 /* wait for state transition */
4852 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4853 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4855 if (ret == GST_STATE_CHANGE_FAILURE) {
4856 LOGE(" [%s] state : %s pending : %s",
4857 GST_ELEMENT_NAME(element),
4858 gst_element_state_get_name(element_state),
4859 gst_element_state_get_name(element_pending_state));
4861 /* dump state of all element */
4862 _mmplayer_dump_pipeline_state(player);
4867 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4872 _mmplayer_destroy(MMHandleType handle)
4874 mmplayer_t *player = MM_PLAYER_CAST(handle);
4878 /* check player handle */
4879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4881 /* destroy can called at anytime */
4882 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4884 /* check async state transition */
4885 __mmplayer_check_async_state_transition(player);
4887 /* release gapless play thread */
4888 if (player->gapless_play_thread) {
4889 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4890 player->gapless_play_thread_exit = TRUE;
4891 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4892 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4894 LOGD("waitting for gapless play thread exit");
4895 g_thread_join(player->gapless_play_thread);
4896 g_mutex_clear(&player->gapless_play_thread_mutex);
4897 g_cond_clear(&player->gapless_play_thread_cond);
4898 LOGD("gapless play thread released");
4901 _mmplayer_release_video_capture(player);
4903 /* de-initialize resource manager */
4904 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4905 player->resource_manager))
4906 LOGE("failed to deinitialize resource manager");
4908 /* release pipeline */
4909 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4910 LOGE("failed to destory pipeline");
4911 return MM_ERROR_PLAYER_INTERNAL;
4914 g_queue_free(player->bus_msg_q);
4916 /* release subtitle info lock and cond */
4917 g_mutex_clear(&player->subtitle_info_mutex);
4918 g_cond_clear(&player->subtitle_info_cond);
4920 __mmplayer_release_dump_list(player->dump_list);
4922 /* release miscellaneous information */
4923 __mmplayer_release_misc(player);
4925 /* release miscellaneous information.
4926 these info needs to be released after pipeline is destroyed. */
4927 __mmplayer_release_misc_post(player);
4929 /* release attributes */
4930 _mmplayer_deconstruct_attribute(handle);
4933 g_mutex_clear(&player->fsink_lock);
4936 g_mutex_clear(&player->update_tag_lock);
4938 /* release video bo lock and cond */
4939 g_mutex_clear(&player->video_bo_mutex);
4940 g_cond_clear(&player->video_bo_cond);
4944 return MM_ERROR_NONE;
4948 _mmplayer_realize(MMHandleType hplayer)
4950 mmplayer_t *player = (mmplayer_t *)hplayer;
4953 MMHandleType attrs = 0;
4954 int ret = MM_ERROR_NONE;
4958 /* check player handle */
4959 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4961 /* check current state */
4962 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4964 attrs = MMPLAYER_GET_ATTRS(player);
4966 LOGE("fail to get attributes.");
4967 return MM_ERROR_PLAYER_INTERNAL;
4969 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4970 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4972 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4973 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4975 if (ret != MM_ERROR_NONE) {
4976 LOGE("failed to parse profile");
4981 if (uri && (strstr(uri, "es_buff://"))) {
4982 if (strstr(uri, "es_buff://push_mode"))
4983 player->es_player_push_mode = TRUE;
4985 player->es_player_push_mode = FALSE;
4988 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4989 LOGW("mms protocol is not supported format.");
4990 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4993 if (MMPLAYER_IS_STREAMING(player))
4994 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4996 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4998 player->smooth_streaming = FALSE;
4999 player->videodec_linked = 0;
5000 player->audiodec_linked = 0;
5001 player->textsink_linked = 0;
5002 player->is_external_subtitle_present = FALSE;
5003 player->is_external_subtitle_added_now = FALSE;
5004 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5005 player->video360_metadata.is_spherical = -1;
5006 player->is_openal_plugin_used = FALSE;
5007 player->demux_pad_index = 0;
5008 player->subtitle_language_list = NULL;
5009 player->is_subtitle_force_drop = FALSE;
5011 _mmplayer_track_initialize(player);
5012 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5014 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5015 gint prebuffer_ms = 0, rebuffer_ms = 0;
5017 player->streamer = _mm_player_streaming_create();
5018 _mm_player_streaming_initialize(player->streamer, TRUE);
5020 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5021 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5023 if (prebuffer_ms > 0) {
5024 prebuffer_ms = MAX(prebuffer_ms, 1000);
5025 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5028 if (rebuffer_ms > 0) {
5029 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5030 rebuffer_ms = MAX(rebuffer_ms, 1000);
5031 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5034 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5035 player->streamer->buffering_req.rebuffer_time);
5038 /* realize pipeline */
5039 ret = __mmplayer_gst_realize(player);
5040 if (ret != MM_ERROR_NONE)
5041 LOGE("fail to realize the player.");
5043 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5051 _mmplayer_unrealize(MMHandleType hplayer)
5053 mmplayer_t *player = (mmplayer_t *)hplayer;
5054 int ret = MM_ERROR_NONE;
5058 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5060 MMPLAYER_CMD_UNLOCK(player);
5061 /* destroy the gst bus msg thread which is created during realize.
5062 this funct have to be called before getting cmd lock. */
5063 _mmplayer_bus_msg_thread_destroy(player);
5064 MMPLAYER_CMD_LOCK(player);
5066 /* check current state */
5067 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5069 /* check async state transition */
5070 __mmplayer_check_async_state_transition(player);
5072 /* unrealize pipeline */
5073 ret = __mmplayer_gst_unrealize(player);
5075 if (!player->interrupted_by_resource) {
5076 int rm_ret = MM_ERROR_NONE;
5077 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5079 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5080 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5081 if (rm_ret != MM_ERROR_NONE)
5082 LOGE("failed to release [%d] resources", res_idx);
5091 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5093 mmplayer_t *player = (mmplayer_t *)hplayer;
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5097 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5101 _mmplayer_get_state(MMHandleType hplayer, int *state)
5103 mmplayer_t *player = (mmplayer_t *)hplayer;
5105 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5107 *state = MMPLAYER_CURRENT_STATE(player);
5109 return MM_ERROR_NONE;
5113 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5115 GstElement *vol_element = NULL;
5116 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5120 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5122 /* check pipeline handle */
5123 if (!player->pipeline || !player->pipeline->audiobin) {
5124 LOGD("'%s' will be applied when audiobin is created", prop_name);
5126 /* NOTE : stored value will be used in create_audiobin
5127 * returning MM_ERROR_NONE here makes application to able to
5128 * set audio volume or mute at anytime.
5130 return MM_ERROR_NONE;
5133 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5134 volume_elem_id = MMPLAYER_A_SINK;
5136 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5138 LOGE("failed to get vol element %d", volume_elem_id);
5139 return MM_ERROR_PLAYER_INTERNAL;
5142 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5144 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5145 LOGE("there is no '%s' property", prop_name);
5146 return MM_ERROR_PLAYER_INTERNAL;
5149 if (!strcmp(prop_name, "volume")) {
5150 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5151 } else if (!strcmp(prop_name, "mute")) {
5152 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5154 LOGE("invalid property %s", prop_name);
5155 return MM_ERROR_PLAYER_INTERNAL;
5158 return MM_ERROR_NONE;
5162 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5164 int ret = MM_ERROR_NONE;
5165 mmplayer_t *player = (mmplayer_t *)hplayer;
5168 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5170 LOGD("volume = %f", volume);
5172 /* invalid factor range or not */
5173 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5174 LOGE("Invalid volume value");
5175 return MM_ERROR_INVALID_ARGUMENT;
5178 player->sound.volume = volume;
5180 ret = __mmplayer_gst_set_volume_property(player, "volume");
5187 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5189 mmplayer_t *player = (mmplayer_t *)hplayer;
5193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5194 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5196 *volume = player->sound.volume;
5198 LOGD("current vol = %f", *volume);
5201 return MM_ERROR_NONE;
5205 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5207 int ret = MM_ERROR_NONE;
5208 mmplayer_t *player = (mmplayer_t *)hplayer;
5211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5213 LOGD("mute = %d", mute);
5215 player->sound.mute = mute;
5217 ret = __mmplayer_gst_set_volume_property(player, "mute");
5224 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5226 mmplayer_t *player = (mmplayer_t *)hplayer;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5233 *mute = player->sound.mute;
5235 LOGD("current mute = %d", *mute);
5239 return MM_ERROR_NONE;
5243 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5245 mmplayer_t *player = (mmplayer_t *)hplayer;
5249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5251 player->audio_stream_changed_cb = callback;
5252 player->audio_stream_changed_cb_user_param = user_param;
5253 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5257 return MM_ERROR_NONE;
5261 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5269 player->audio_decoded_cb = callback;
5270 player->audio_decoded_cb_user_param = user_param;
5271 player->audio_extract_opt = opt;
5272 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 if (callback && !player->bufmgr)
5289 player->bufmgr = tbm_bufmgr_init(-1);
5291 player->set_mode.video_export = (callback) ? true : false;
5292 player->video_decoded_cb = callback;
5293 player->video_decoded_cb_user_param = user_param;
5295 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5299 return MM_ERROR_NONE;
5303 _mmplayer_start(MMHandleType hplayer)
5305 mmplayer_t *player = (mmplayer_t *)hplayer;
5306 gint ret = MM_ERROR_NONE;
5310 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5312 /* check current state */
5313 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5315 /* start pipeline */
5316 ret = _mmplayer_gst_start(player);
5317 if (ret != MM_ERROR_NONE)
5318 LOGE("failed to start player.");
5320 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5321 LOGD("force playing start even during buffering");
5322 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5330 /* NOTE: post "not supported codec message" to application
5331 * when one codec is not found during AUTOPLUGGING in MSL.
5332 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5333 * And, if any codec is not found, don't send message here.
5334 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5337 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5339 MMMessageParamType msg_param;
5340 memset(&msg_param, 0, sizeof(MMMessageParamType));
5341 gboolean post_msg_direct = FALSE;
5345 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5347 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5348 player->not_supported_codec, player->can_support_codec);
5350 if (player->not_found_demuxer) {
5351 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5352 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5354 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5355 MMPLAYER_FREEIF(msg_param.data);
5357 return MM_ERROR_NONE;
5360 if (player->not_supported_codec) {
5361 if (player->can_support_codec) {
5362 // There is one codec to play
5363 post_msg_direct = TRUE;
5365 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5366 post_msg_direct = TRUE;
5369 if (post_msg_direct) {
5370 MMMessageParamType msg_param;
5371 memset(&msg_param, 0, sizeof(MMMessageParamType));
5373 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5374 LOGW("not found AUDIO codec, posting error code to application.");
5376 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5377 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5378 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5379 LOGW("not found VIDEO codec, posting error code to application.");
5381 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5382 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5385 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5387 MMPLAYER_FREEIF(msg_param.data);
5389 return MM_ERROR_NONE;
5391 // no any supported codec case
5392 LOGW("not found any codec, posting error code to application.");
5394 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5395 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5396 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5398 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5399 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5402 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5404 MMPLAYER_FREEIF(msg_param.data);
5410 return MM_ERROR_NONE;
5414 __mmplayer_check_pipeline(mmplayer_t *player)
5416 GstState element_state = GST_STATE_VOID_PENDING;
5417 GstState element_pending_state = GST_STATE_VOID_PENDING;
5419 int ret = MM_ERROR_NONE;
5421 if (!player->gapless.reconfigure)
5424 LOGW("pipeline is under construction.");
5426 MMPLAYER_PLAYBACK_LOCK(player);
5427 MMPLAYER_PLAYBACK_UNLOCK(player);
5429 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5431 /* wait for state transition */
5432 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5433 if (ret == GST_STATE_CHANGE_FAILURE)
5434 LOGE("failed to change pipeline state within %d sec", timeout);
5437 /* NOTE : it should be able to call 'stop' anytime*/
5439 _mmplayer_stop(MMHandleType hplayer)
5441 mmplayer_t *player = (mmplayer_t *)hplayer;
5442 int ret = MM_ERROR_NONE;
5446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5448 /* check current state */
5449 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5451 /* check pipline building state */
5452 __mmplayer_check_pipeline(player);
5453 __mmplayer_reset_gapless_state(player);
5455 /* NOTE : application should not wait for EOS after calling STOP */
5456 _mmplayer_cancel_eos_timer(player);
5459 player->seek_state = MMPLAYER_SEEK_NONE;
5462 ret = _mmplayer_gst_stop(player);
5464 if (ret != MM_ERROR_NONE)
5465 LOGE("failed to stop player.");
5473 _mmplayer_pause(MMHandleType hplayer)
5475 mmplayer_t *player = (mmplayer_t *)hplayer;
5476 gint64 pos_nsec = 0;
5477 gboolean async = FALSE;
5478 gint ret = MM_ERROR_NONE;
5482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5484 /* check current state */
5485 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5487 /* check pipline building state */
5488 __mmplayer_check_pipeline(player);
5490 switch (MMPLAYER_CURRENT_STATE(player)) {
5491 case MM_PLAYER_STATE_READY:
5493 /* check prepare async or not.
5494 * In the case of streaming playback, it's recommned to avoid blocking wait.
5496 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5497 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5499 /* Changing back sync of rtspsrc to async */
5500 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5501 LOGD("async prepare working mode for rtsp");
5507 case MM_PLAYER_STATE_PLAYING:
5509 /* NOTE : store current point to overcome some bad operation
5510 *(returning zero when getting current position in paused state) of some
5513 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5514 LOGW("getting current position failed in paused");
5516 player->last_position = pos_nsec;
5518 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5519 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5520 This causes problem is position calculation during normal pause resume scenarios also.
5521 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5522 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5523 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5524 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5530 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5531 LOGD("doing async pause in case of ms buff src");
5535 /* pause pipeline */
5536 ret = _mmplayer_gst_pause(player, async);
5538 if (ret != MM_ERROR_NONE)
5539 LOGE("failed to pause player. ret : 0x%x", ret);
5541 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5542 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5543 LOGE("failed to update display_rotation");
5551 /* in case of streaming, pause could take long time.*/
5553 _mmplayer_abort_pause(MMHandleType hplayer)
5555 mmplayer_t *player = (mmplayer_t *)hplayer;
5556 int ret = MM_ERROR_NONE;
5560 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5562 player->pipeline->mainbin,
5563 MM_ERROR_PLAYER_NOT_INITIALIZED);
5565 LOGD("set the pipeline state to READY");
5567 /* set state to READY */
5568 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5569 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5570 if (ret != MM_ERROR_NONE) {
5571 LOGE("fail to change state to READY");
5572 return MM_ERROR_PLAYER_INTERNAL;
5575 LOGD("succeeded in changing state to READY");
5580 _mmplayer_resume(MMHandleType hplayer)
5582 mmplayer_t *player = (mmplayer_t *)hplayer;
5583 int ret = MM_ERROR_NONE;
5584 gboolean async = FALSE;
5588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5590 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5591 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5592 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5596 /* Changing back sync mode rtspsrc to async */
5597 LOGD("async resume for rtsp case");
5601 /* check current state */
5602 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5604 ret = _mmplayer_gst_resume(player, async);
5605 if (ret != MM_ERROR_NONE)
5606 LOGE("failed to resume player.");
5608 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5609 LOGD("force resume even during buffering");
5610 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5619 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5621 mmplayer_t *player = (mmplayer_t *)hplayer;
5622 gint64 pos_nsec = 0;
5623 int ret = MM_ERROR_NONE;
5625 signed long long start = 0, stop = 0;
5626 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5629 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5630 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5632 /* The sound of video is not supported under 0.0 and over 2.0. */
5633 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5634 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5637 _mmplayer_set_mute(hplayer, mute);
5639 if (player->playback_rate == rate)
5640 return MM_ERROR_NONE;
5642 /* If the position is reached at start potion during fast backward, EOS is posted.
5643 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5645 player->playback_rate = rate;
5647 current_state = MMPLAYER_CURRENT_STATE(player);
5649 if (current_state != MM_PLAYER_STATE_PAUSED)
5650 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5652 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5654 if ((current_state == MM_PLAYER_STATE_PAUSED)
5655 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5656 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5657 pos_nsec = player->last_position;
5662 stop = GST_CLOCK_TIME_NONE;
5664 start = GST_CLOCK_TIME_NONE;
5668 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5669 player->playback_rate,
5671 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5672 GST_SEEK_TYPE_SET, start,
5673 GST_SEEK_TYPE_SET, stop)) {
5674 LOGE("failed to set speed playback");
5675 return MM_ERROR_PLAYER_SEEK;
5678 LOGD("succeeded to set speed playback as %0.1f", rate);
5682 return MM_ERROR_NONE;;
5686 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5688 mmplayer_t *player = (mmplayer_t *)hplayer;
5689 int ret = MM_ERROR_NONE;
5693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5695 /* check pipline building state */
5696 __mmplayer_check_pipeline(player);
5698 ret = _mmplayer_gst_set_position(player, position, FALSE);
5706 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5708 mmplayer_t *player = (mmplayer_t *)hplayer;
5709 int ret = MM_ERROR_NONE;
5711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5714 if (g_strrstr(player->type, "video/mpegts"))
5715 __mmplayer_update_duration_value(player);
5717 *duration = player->duration;
5722 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5724 mmplayer_t *player = (mmplayer_t *)hplayer;
5725 int ret = MM_ERROR_NONE;
5727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5729 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5735 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5737 mmplayer_t *player = (mmplayer_t *)hplayer;
5738 int ret = MM_ERROR_NONE;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5744 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5752 __mmplayer_is_midi_type(gchar *str_caps)
5754 if ((g_strrstr(str_caps, "audio/midi")) ||
5755 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5756 (g_strrstr(str_caps, "application/x-smaf")) ||
5757 (g_strrstr(str_caps, "audio/x-imelody")) ||
5758 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5759 (g_strrstr(str_caps, "audio/xmf")) ||
5760 (g_strrstr(str_caps, "audio/mxmf"))) {
5769 __mmplayer_is_only_mp3_type(gchar *str_caps)
5771 if (g_strrstr(str_caps, "application/x-id3") ||
5772 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5778 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5780 GstStructure *caps_structure = NULL;
5781 gint samplerate = 0;
5785 MMPLAYER_RETURN_IF_FAIL(player && caps);
5787 caps_structure = gst_caps_get_structure(caps, 0);
5789 /* set stream information */
5790 gst_structure_get_int(caps_structure, "rate", &samplerate);
5791 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5793 gst_structure_get_int(caps_structure, "channels", &channels);
5794 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5796 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5800 __mmplayer_update_content_type_info(mmplayer_t *player)
5803 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5805 if (__mmplayer_is_midi_type(player->type)) {
5806 player->bypass_audio_effect = TRUE;
5810 if (!player->streamer) {
5811 LOGD("no need to check streaming type");
5815 if (g_strrstr(player->type, "application/x-hls")) {
5816 /* If it can't know exact type when it parses uri because of redirection case,
5817 * it will be fixed by typefinder or when doing autoplugging.
5819 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5820 player->streamer->is_adaptive_streaming = TRUE;
5821 } else if (g_strrstr(player->type, "application/dash+xml")) {
5822 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5823 player->streamer->is_adaptive_streaming = TRUE;
5826 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5827 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5828 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5830 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5831 if (player->streamer->is_adaptive_streaming)
5832 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5834 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5838 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5843 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5844 GstCaps *caps, gpointer data)
5846 mmplayer_t *player = (mmplayer_t *)data;
5851 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5853 /* store type string */
5854 MMPLAYER_FREEIF(player->type);
5855 player->type = gst_caps_to_string(caps);
5857 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5858 player, player->type, probability, gst_caps_get_size(caps));
5860 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5861 (g_strrstr(player->type, "audio/x-raw-int"))) {
5862 LOGE("not support media format");
5864 if (player->msg_posted == FALSE) {
5865 MMMessageParamType msg_param;
5866 memset(&msg_param, 0, sizeof(MMMessageParamType));
5868 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5869 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5871 /* don't post more if one was sent already */
5872 player->msg_posted = TRUE;
5877 __mmplayer_update_content_type_info(player);
5879 pad = gst_element_get_static_pad(tf, "src");
5881 LOGE("fail to get typefind src pad.");
5885 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5886 gboolean async = FALSE;
5887 LOGE("failed to autoplug %s", player->type);
5889 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5891 if (async && player->msg_posted == FALSE)
5892 __mmplayer_handle_missed_plugin(player);
5896 gst_object_unref(GST_OBJECT(pad));
5904 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5906 GstElement *decodebin = NULL;
5910 /* create decodebin */
5911 decodebin = gst_element_factory_make("decodebin", NULL);
5914 LOGE("fail to create decodebin");
5918 /* raw pad handling signal */
5919 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5920 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5922 /* no-more-pad pad handling signal */
5923 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5924 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5926 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5927 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5929 /* This signal is emitted when a pad for which there is no further possible
5930 decoding is added to the decodebin.*/
5931 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5932 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5934 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5935 before looking for any elements that can handle that stream.*/
5936 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5937 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5939 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5940 before looking for any elements that can handle that stream.*/
5941 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5942 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5944 /* This signal is emitted once decodebin has finished decoding all the data.*/
5945 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5946 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5948 /* This signal is emitted when a element is added to the bin.*/
5949 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5950 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5957 __mmplayer_gst_make_queue2(mmplayer_t *player)
5959 GstElement *queue2 = NULL;
5960 gint64 dur_bytes = 0L;
5961 mmplayer_gst_element_t *mainbin = NULL;
5962 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5965 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5967 mainbin = player->pipeline->mainbin;
5969 queue2 = gst_element_factory_make("queue2", "queue2");
5971 LOGE("failed to create buffering queue element");
5975 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5976 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5978 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5980 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5981 * skip the pull mode(file or ring buffering) setting. */
5982 if (dur_bytes > 0) {
5983 if (!g_strrstr(player->type, "video/mpegts")) {
5984 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5985 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5991 _mm_player_streaming_set_queue2(player->streamer,
5995 (guint64)dur_bytes); /* no meaning at the moment */
6001 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6003 mmplayer_gst_element_t *mainbin = NULL;
6004 GstElement *decodebin = NULL;
6005 GstElement *queue2 = NULL;
6006 GstPad *sinkpad = NULL;
6007 GstPad *qsrcpad = NULL;
6010 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6012 mainbin = player->pipeline->mainbin;
6014 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6016 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6017 LOGW("need to check: muxed buffer is not null");
6020 queue2 = __mmplayer_gst_make_queue2(player);
6022 LOGE("failed to make queue2");
6026 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6027 LOGE("failed to add buffering queue");
6031 sinkpad = gst_element_get_static_pad(queue2, "sink");
6032 qsrcpad = gst_element_get_static_pad(queue2, "src");
6034 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6035 LOGE("failed to link [%s:%s]-[%s:%s]",
6036 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6040 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6041 LOGE("failed to sync queue2 state with parent");
6045 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6046 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6050 gst_object_unref(GST_OBJECT(sinkpad));
6054 /* create decodebin */
6055 decodebin = _mmplayer_gst_make_decodebin(player);
6057 LOGE("failed to make decodebin");
6061 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6062 LOGE("failed to add decodebin");
6066 /* to force caps on the decodebin element and avoid reparsing stuff by
6067 * typefind. It also avoids a deadlock in the way typefind activates pads in
6068 * the state change */
6069 g_object_set(decodebin, "sink-caps", caps, NULL);
6071 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6073 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6074 LOGE("failed to link [%s:%s]-[%s:%s]",
6075 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6079 gst_object_unref(GST_OBJECT(sinkpad));
6081 gst_object_unref(GST_OBJECT(qsrcpad));
6084 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6085 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6087 /* set decodebin property about buffer in streaming playback. *
6088 * in case of HLS/DASH, it does not need to have big buffer *
6089 * because it is kind of adaptive streaming. */
6090 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6091 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6092 gint high_percent = 0;
6094 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6095 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6097 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6099 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6101 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6102 "high-percent", high_percent,
6103 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6104 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6105 "max-size-buffers", 0, NULL); // disable or automatic
6108 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6109 LOGE("failed to sync decodebin state with parent");
6120 gst_object_unref(GST_OBJECT(sinkpad));
6123 gst_object_unref(GST_OBJECT(qsrcpad));
6126 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6127 * You need to explicitly set elements to the NULL state before
6128 * dropping the final reference, to allow them to clean up.
6130 gst_element_set_state(queue2, GST_STATE_NULL);
6132 /* And, it still has a parent "player".
6133 * You need to let the parent manage the object instead of unreffing the object directly.
6135 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6136 gst_object_unref(queue2);
6141 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6142 * You need to explicitly set elements to the NULL state before
6143 * dropping the final reference, to allow them to clean up.
6145 gst_element_set_state(decodebin, GST_STATE_NULL);
6147 /* And, it still has a parent "player".
6148 * You need to let the parent manage the object instead of unreffing the object directly.
6151 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6152 gst_object_unref(decodebin);
6160 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6165 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6167 LOGD("class : %s, mime : %s", factory_class, mime);
6169 /* add missing plugin */
6170 /* NOTE : msl should check missing plugin for image mime type.
6171 * Some motion jpeg clips can have playable audio track.
6172 * So, msl have to play audio after displaying popup written video format not supported.
6174 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6175 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6176 LOGD("not found demuxer");
6177 player->not_found_demuxer = TRUE;
6178 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6184 if (!g_strrstr(factory_class, "Demuxer")) {
6185 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6186 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6187 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6189 /* check that clip have multi tracks or not */
6190 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6191 LOGD("video plugin is already linked");
6193 LOGW("add VIDEO to missing plugin");
6194 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6195 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6197 } else if (g_str_has_prefix(mime, "audio")) {
6198 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6199 LOGD("audio plugin is already linked");
6201 LOGW("add AUDIO to missing plugin");
6202 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6203 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6211 return MM_ERROR_NONE;
6215 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6217 mmplayer_t *player = (mmplayer_t *)data;
6221 MMPLAYER_RETURN_IF_FAIL(player);
6223 /* remove fakesink. */
6224 if (!_mmplayer_gst_remove_fakesink(player,
6225 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6226 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6227 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6228 * source element are not same. To overcome this situation, this function will called
6229 * several places and several times. Therefore, this is not an error case.
6234 LOGD("[handle: %p] pipeline has completely constructed", player);
6236 if ((player->ini.async_start) &&
6237 (player->msg_posted == FALSE) &&
6238 (player->cmd >= MMPLAYER_COMMAND_START))
6239 __mmplayer_handle_missed_plugin(player);
6241 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6245 __mmplayer_check_profile(void)
6248 static int profile_tv = -1;
6250 if (__builtin_expect(profile_tv != -1, 1))
6253 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6254 switch (*profileName) {
6269 __mmplayer_get_next_uri(mmplayer_t *player)
6271 mmplayer_parse_profile_t profile;
6273 guint num_of_list = 0;
6276 num_of_list = g_list_length(player->uri_info.uri_list);
6277 uri_idx = player->uri_info.uri_idx;
6279 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6280 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6281 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6283 LOGW("next uri does not exist");
6287 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6288 LOGE("failed to parse profile");
6292 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6293 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6294 LOGW("uri type is not supported(%d)", profile.uri_type);
6298 LOGD("success to find next uri %d", uri_idx);
6302 if (uri_idx == num_of_list) {
6303 LOGE("failed to find next uri");
6307 player->uri_info.uri_idx = uri_idx;
6308 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6310 if (mm_attrs_commit_all(player->attrs)) {
6311 LOGE("failed to commit");
6315 SECURE_LOGD("next playback uri: %s", uri);
6320 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6322 #define REPEAT_COUNT_INFINITE -1
6323 #define REPEAT_COUNT_MIN 2
6324 #define ORIGINAL_URI_ONLY 1
6326 MMHandleType attrs = 0;
6330 guint num_of_uri = 0;
6331 int profile_tv = -1;
6335 LOGD("checking for gapless play option");
6337 if (player->build_audio_offload) {
6338 LOGE("offload path is not supportable.");
6342 if (player->pipeline->textbin) {
6343 LOGE("subtitle path is enabled. gapless play is not supported.");
6347 attrs = MMPLAYER_GET_ATTRS(player);
6349 LOGE("fail to get attributes.");
6353 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6355 /* gapless playback is not supported in case of video at TV profile. */
6356 profile_tv = __mmplayer_check_profile();
6357 if (profile_tv && video) {
6358 LOGW("not support video gapless playback");
6362 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6363 LOGE("failed to get play count");
6365 if (mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless) != MM_ERROR_NONE)
6366 LOGE("failed to get gapless mode");
6368 /* check repeat count in case of audio */
6370 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6371 LOGW("gapless is disabled");
6375 num_of_uri = g_list_length(player->uri_info.uri_list);
6377 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6379 if (num_of_uri == ORIGINAL_URI_ONLY) {
6380 /* audio looping path */
6381 if (count >= REPEAT_COUNT_MIN) {
6382 /* decrease play count */
6383 /* we succeeded to rewind. update play count and then wait for next EOS */
6385 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6386 /* commit attribute */
6387 if (mm_attrs_commit_all(attrs))
6388 LOGE("failed to commit attribute");
6390 } else if (count != REPEAT_COUNT_INFINITE) {
6391 LOGD("there is no next uri and no repeat");
6394 LOGD("looping cnt %d", count);
6396 /* gapless playback path */
6397 if (!__mmplayer_get_next_uri(player)) {
6398 LOGE("failed to get next uri");
6405 LOGE("unable to play gapless path. EOS will be posted soon");
6410 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6412 mmplayer_selector_t *selector = &player->selector[type];
6413 mmplayer_gst_element_t *sinkbin = NULL;
6414 main_element_id_e selectorId = MMPLAYER_M_NUM;
6415 main_element_id_e sinkId = MMPLAYER_M_NUM;
6416 GstPad *srcpad = NULL;
6417 GstPad *sinkpad = NULL;
6418 gboolean send_notice = FALSE;
6421 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6423 LOGD("type %d", type);
6426 case MM_PLAYER_TRACK_TYPE_AUDIO:
6427 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6428 sinkId = MMPLAYER_A_BIN;
6429 sinkbin = player->pipeline->audiobin;
6431 case MM_PLAYER_TRACK_TYPE_VIDEO:
6432 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6433 sinkId = MMPLAYER_V_BIN;
6434 sinkbin = player->pipeline->videobin;
6437 case MM_PLAYER_TRACK_TYPE_TEXT:
6438 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6439 sinkId = MMPLAYER_T_BIN;
6440 sinkbin = player->pipeline->textbin;
6443 LOGE("requested type is not supportable");
6448 if (player->pipeline->mainbin[selectorId].gst) {
6451 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6453 if (selector->event_probe_id != 0)
6454 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6455 selector->event_probe_id = 0;
6457 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6458 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6460 if (srcpad && sinkpad) {
6461 /* after getting drained signal there is no data flows, so no need to do pad_block */
6462 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6463 gst_pad_unlink(srcpad, sinkpad);
6465 /* send custom event to sink pad to handle it at video sink */
6467 LOGD("send custom event to sinkpad");
6468 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6469 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6470 gst_pad_send_event(sinkpad, event);
6474 gst_object_unref(sinkpad);
6477 gst_object_unref(srcpad);
6480 LOGD("selector release");
6482 /* release and unref requests pad from the selector */
6483 for (n = 0; n < selector->channels->len; n++) {
6484 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6485 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6487 g_ptr_array_set_size(selector->channels, 0);
6489 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6490 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6492 player->pipeline->mainbin[selectorId].gst = NULL;
6500 __mmplayer_deactivate_old_path(mmplayer_t *player)
6503 MMPLAYER_RETURN_IF_FAIL(player);
6505 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6506 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6507 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6508 LOGE("deactivate selector error");
6512 _mmplayer_track_destroy(player);
6513 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6515 if (player->streamer) {
6516 _mm_player_streaming_initialize(player->streamer, FALSE);
6517 _mm_player_streaming_destroy(player->streamer);
6518 player->streamer = NULL;
6521 MMPLAYER_PLAYBACK_LOCK(player);
6522 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6529 if (!player->msg_posted) {
6530 MMMessageParamType msg = {0,};
6533 msg.code = MM_ERROR_PLAYER_INTERNAL;
6534 LOGE("gapless_uri_play> deactivate error");
6536 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6537 player->msg_posted = TRUE;
6543 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6545 int result = MM_ERROR_NONE;
6546 mmplayer_t *player = (mmplayer_t *)hplayer;
6549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6551 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6552 if (mm_attrs_commit_all(player->attrs)) {
6553 LOGE("failed to commit the original uri.");
6554 result = MM_ERROR_PLAYER_INTERNAL;
6556 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6557 LOGE("failed to add the original uri in the uri list.");
6565 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6567 mmplayer_t *player = (mmplayer_t *)hplayer;
6568 guint num_of_list = 0;
6572 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6573 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6575 if (player->pipeline && player->pipeline->textbin) {
6576 LOGE("subtitle path is enabled.");
6577 return MM_ERROR_PLAYER_INVALID_STATE;
6580 num_of_list = g_list_length(player->uri_info.uri_list);
6582 if (is_first_path) {
6583 if (num_of_list == 0) {
6584 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6585 SECURE_LOGD("add original path : %s", uri);
6587 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6588 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6590 SECURE_LOGD("change original path : %s", uri);
6593 MMHandleType attrs = 0;
6594 attrs = MMPLAYER_GET_ATTRS(player);
6596 if (num_of_list == 0) {
6597 char *original_uri = NULL;
6600 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6602 if (!original_uri) {
6603 LOGE("there is no original uri.");
6604 return MM_ERROR_PLAYER_INVALID_STATE;
6607 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6608 player->uri_info.uri_idx = 0;
6610 SECURE_LOGD("add original path at first : %s", original_uri);
6614 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6615 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6619 return MM_ERROR_NONE;
6623 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6625 mmplayer_t *player = (mmplayer_t *)hplayer;
6626 char *next_uri = NULL;
6627 guint num_of_list = 0;
6630 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6632 num_of_list = g_list_length(player->uri_info.uri_list);
6634 if (num_of_list > 0) {
6635 gint uri_idx = player->uri_info.uri_idx;
6637 if (uri_idx < num_of_list-1)
6642 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6643 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6645 *uri = g_strdup(next_uri);
6649 return MM_ERROR_NONE;
6653 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6654 GstCaps *caps, gpointer data)
6656 mmplayer_t *player = (mmplayer_t *)data;
6657 const gchar *klass = NULL;
6658 const gchar *mime = NULL;
6659 gchar *caps_str = NULL;
6661 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6662 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6663 caps_str = gst_caps_to_string(caps);
6665 LOGW("unknown type of caps : %s from %s",
6666 caps_str, GST_ELEMENT_NAME(elem));
6668 MMPLAYER_FREEIF(caps_str);
6670 /* There is no available codec. */
6671 __mmplayer_check_not_supported_codec(player, klass, mime);
6675 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6676 GstCaps *caps, gpointer data)
6678 mmplayer_t *player = (mmplayer_t *)data;
6679 const char *mime = NULL;
6680 gboolean ret = TRUE;
6682 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6683 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6685 if (g_str_has_prefix(mime, "audio")) {
6686 GstStructure *caps_structure = NULL;
6687 gint samplerate = 0;
6689 gchar *caps_str = NULL;
6691 caps_structure = gst_caps_get_structure(caps, 0);
6692 gst_structure_get_int(caps_structure, "rate", &samplerate);
6693 gst_structure_get_int(caps_structure, "channels", &channels);
6695 if ((channels > 0 && samplerate == 0)) {
6696 LOGD("exclude audio...");
6700 caps_str = gst_caps_to_string(caps);
6701 /* set it directly because not sent by TAG */
6702 if (g_strrstr(caps_str, "mobile-xmf"))
6703 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6704 MMPLAYER_FREEIF(caps_str);
6705 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6706 MMMessageParamType msg_param;
6707 memset(&msg_param, 0, sizeof(MMMessageParamType));
6708 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6709 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6710 LOGD("video file is not supported on this device");
6712 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6713 LOGD("already video linked");
6716 LOGD("found new stream");
6723 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6725 gboolean ret = TRUE;
6726 GDBusConnection *conn = NULL;
6728 GVariant *result = NULL;
6729 const gchar *dbus_device_type = NULL;
6730 const gchar *dbus_ret = NULL;
6733 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6735 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6741 result = g_dbus_connection_call_sync(conn,
6742 "org.pulseaudio.Server",
6743 "/org/pulseaudio/StreamManager",
6744 "org.pulseaudio.StreamManager",
6745 "GetCurrentMediaRoutingPath",
6746 g_variant_new("(s)", "out"),
6747 G_VARIANT_TYPE("(ss)"),
6748 G_DBUS_CALL_FLAGS_NONE,
6752 if (!result || err) {
6753 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6759 /* device type is listed in stream-map.json at mmfw-sysconf */
6760 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6762 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6763 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6768 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6769 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6770 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6771 LOGD("audio offload is supportable");
6777 LOGD("audio offload is not supportable");
6781 g_variant_unref(result);
6782 g_object_unref(conn);
6787 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6789 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6790 gint64 position = 0;
6792 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6793 player->pipeline && player->pipeline->mainbin);
6795 MMPLAYER_CMD_LOCK(player);
6796 current_state = MMPLAYER_CURRENT_STATE(player);
6798 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6799 LOGW("getting current position failed in paused");
6801 _mmplayer_unrealize((MMHandleType)player);
6802 _mmplayer_realize((MMHandleType)player);
6804 _mmplayer_set_position((MMHandleType)player, position);
6806 /* async not to be blocked in streaming case */
6807 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6808 if (mm_attrs_commit_all(player->attrs))
6809 LOGE("failed to commit");
6811 _mmplayer_pause((MMHandleType)player);
6813 if (current_state == MM_PLAYER_STATE_PLAYING)
6814 _mmplayer_start((MMHandleType)player);
6815 MMPLAYER_CMD_UNLOCK(player);
6817 LOGD("rebuilding audio pipeline is completed.");
6820 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6822 mmplayer_t *player = (mmplayer_t *)user_data;
6823 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6824 gboolean is_supportable = FALSE;
6826 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6827 LOGW("failed to get device type");
6829 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6831 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6832 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6833 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6834 LOGD("ignore this dev connected info");
6838 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6839 if (player->build_audio_offload == is_supportable) {
6840 LOGD("keep current pipeline without re-building");
6844 /* rebuild pipeline */
6845 LOGD("re-build pipeline - offload: %d", is_supportable);
6846 player->build_audio_offload = FALSE;
6847 __mmplayer_rebuild_audio_pipeline(player);
6853 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6855 unsigned int id = 0;
6857 if (player->audio_device_cb_id != 0) {
6858 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6862 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6863 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6864 LOGD("added device connected cb (%u)", id);
6865 player->audio_device_cb_id = id;
6867 LOGW("failed to add device connected cb");
6875 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6877 gboolean ret = FALSE;
6878 GstElementFactory *factory = NULL;
6881 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6883 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6884 if (!__mmplayer_is_only_mp3_type(player->type))
6887 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6888 LOGD("there is no audio offload sink");
6892 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6893 LOGW("there is no audio device type to support offload");
6897 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6899 LOGW("there is no installed audio offload sink element");
6902 gst_object_unref(factory);
6904 if (__mmplayer_acquire_hw_resource(player,
6905 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6906 LOGE("failed to acquire audio offload decoder resource");
6910 if (!__mmplayer_add_audio_device_connected_cb(player))
6913 if (!__mmplayer_is_audio_offload_device_type(player))
6916 LOGD("audio offload can be built");
6921 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6927 static GstAutoplugSelectResult
6928 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6930 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6932 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6933 int audio_offload = 0;
6935 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6936 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6938 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6939 LOGD("expose audio path to build offload output path");
6940 player->build_audio_offload = TRUE;
6941 /* update codec info */
6942 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6943 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6944 player->audiodec_linked = 1;
6946 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6950 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6952 LOGD("audio codec type: %d", codec_type);
6953 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6954 /* sw codec will be skipped */
6955 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6956 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6957 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6958 ret = GST_AUTOPLUG_SELECT_SKIP;
6962 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6963 /* hw codec will be skipped */
6964 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6965 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6966 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6967 ret = GST_AUTOPLUG_SELECT_SKIP;
6972 /* set stream information */
6973 if (!player->audiodec_linked)
6974 __mmplayer_set_audio_attrs(player, caps);
6976 /* update codec info */
6977 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6978 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6979 player->audiodec_linked = 1;
6981 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6983 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6985 LOGD("video codec type: %d", codec_type);
6986 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6987 /* sw codec is skipped */
6988 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6989 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6990 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6991 ret = GST_AUTOPLUG_SELECT_SKIP;
6995 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6996 /* hw codec is skipped */
6997 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6998 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6999 ret = GST_AUTOPLUG_SELECT_SKIP;
7004 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7005 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7007 /* mark video decoder for acquire */
7008 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7009 LOGW("video decoder resource is already acquired, skip it.");
7010 ret = GST_AUTOPLUG_SELECT_SKIP;
7014 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7015 LOGE("failed to acquire video decoder resource");
7016 ret = GST_AUTOPLUG_SELECT_SKIP;
7019 player->interrupted_by_resource = FALSE;
7022 /* update codec info */
7023 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7024 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7025 player->videodec_linked = 1;
7033 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7034 GstCaps *caps, GstElementFactory *factory, gpointer data)
7036 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7037 mmplayer_t *player = (mmplayer_t *)data;
7039 gchar *factory_name = NULL;
7040 gchar *caps_str = NULL;
7041 const gchar *klass = NULL;
7044 factory_name = GST_OBJECT_NAME(factory);
7045 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7046 caps_str = gst_caps_to_string(caps);
7048 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7050 /* store type string */
7051 if (player->type == NULL) {
7052 player->type = gst_caps_to_string(caps);
7053 __mmplayer_update_content_type_info(player);
7056 /* filtering exclude keyword */
7057 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7058 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7059 LOGW("skipping [%s] by exculde keyword [%s]",
7060 factory_name, player->ini.exclude_element_keyword[idx]);
7062 result = GST_AUTOPLUG_SELECT_SKIP;
7067 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7068 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7069 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7070 factory_name, player->ini.unsupported_codec_keyword[idx]);
7071 result = GST_AUTOPLUG_SELECT_SKIP;
7076 /* exclude webm format */
7077 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7078 * because webm format is not supportable.
7079 * If webm is disabled in "autoplug-continue", there is no state change
7080 * failure or error because the decodebin will expose the pad directly.
7081 * It make MSL invoke _prepare_async_callback.
7082 * So, we need to disable webm format in "autoplug-select" */
7083 if (caps_str && strstr(caps_str, "webm")) {
7084 LOGW("webm is not supported");
7085 result = GST_AUTOPLUG_SELECT_SKIP;
7089 /* check factory class for filtering */
7090 /* NOTE : msl don't need to use image plugins.
7091 * So, those plugins should be skipped for error handling.
7093 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7094 LOGD("skipping [%s] by not required", factory_name);
7095 result = GST_AUTOPLUG_SELECT_SKIP;
7099 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7100 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7101 // TO CHECK : subtitle if needed, add subparse exception.
7102 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7103 result = GST_AUTOPLUG_SELECT_SKIP;
7107 if (g_strrstr(factory_name, "mpegpsdemux")) {
7108 LOGD("skipping PS container - not support");
7109 result = GST_AUTOPLUG_SELECT_SKIP;
7113 if (g_strrstr(factory_name, "mssdemux"))
7114 player->smooth_streaming = TRUE;
7116 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7117 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7120 GstStructure *str = NULL;
7121 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7123 /* don't make video because of not required */
7124 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7125 (!player->set_mode.video_export)) {
7126 LOGD("no need video decoding, expose pad");
7127 result = GST_AUTOPLUG_SELECT_EXPOSE;
7131 /* get w/h for omx state-tune */
7132 /* FIXME: deprecated? */
7133 str = gst_caps_get_structure(caps, 0);
7134 gst_structure_get_int(str, "width", &width);
7137 if (player->v_stream_caps) {
7138 gst_caps_unref(player->v_stream_caps);
7139 player->v_stream_caps = NULL;
7142 player->v_stream_caps = gst_caps_copy(caps);
7143 LOGD("take caps for video state tune");
7144 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7148 if (g_strrstr(klass, "Codec/Decoder")) {
7149 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7150 if (result != GST_AUTOPLUG_SELECT_TRY) {
7151 LOGW("skip add decoder");
7157 MMPLAYER_FREEIF(caps_str);
7163 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7166 //mmplayer_t *player = (mmplayer_t *)data;
7167 GstCaps *caps = NULL;
7169 LOGD("[Decodebin2] pad-removed signal");
7171 caps = gst_pad_query_caps(new_pad, NULL);
7173 LOGW("query caps is NULL");
7177 gchar *caps_str = NULL;
7178 caps_str = gst_caps_to_string(caps);
7180 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7182 MMPLAYER_FREEIF(caps_str);
7183 gst_caps_unref(caps);
7187 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7189 mmplayer_t *player = (mmplayer_t *)data;
7190 GstIterator *iter = NULL;
7191 GValue item = { 0, };
7193 gboolean done = FALSE;
7194 gboolean is_all_drained = TRUE;
7197 MMPLAYER_RETURN_IF_FAIL(player);
7199 LOGD("__mmplayer_gst_decode_drained");
7201 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7202 LOGW("Fail to get cmd lock");
7206 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7207 !__mmplayer_verify_gapless_play_path(player)) {
7208 LOGD("decoding is finished.");
7209 __mmplayer_reset_gapless_state(player);
7210 MMPLAYER_CMD_UNLOCK(player);
7214 player->gapless.reconfigure = TRUE;
7216 /* check decodebin src pads whether they received EOS or not */
7217 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7220 switch (gst_iterator_next(iter, &item)) {
7221 case GST_ITERATOR_OK:
7222 pad = g_value_get_object(&item);
7223 if (pad && !GST_PAD_IS_EOS(pad)) {
7224 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7225 is_all_drained = FALSE;
7228 g_value_reset(&item);
7230 case GST_ITERATOR_RESYNC:
7231 gst_iterator_resync(iter);
7233 case GST_ITERATOR_ERROR:
7234 case GST_ITERATOR_DONE:
7239 g_value_unset(&item);
7240 gst_iterator_free(iter);
7242 if (!is_all_drained) {
7243 LOGD("Wait util the all pads get EOS.");
7244 MMPLAYER_CMD_UNLOCK(player);
7249 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7250 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7252 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7253 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7254 __mmplayer_deactivate_old_path(player);
7255 MMPLAYER_CMD_UNLOCK(player);
7261 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7263 mmplayer_t *player = (mmplayer_t *)data;
7264 const gchar *klass = NULL;
7265 gchar *factory_name = NULL;
7267 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7268 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7270 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7272 if (__mmplayer_add_dump_buffer_probe(player, element))
7273 LOGD("add buffer probe");
7275 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7276 gchar *selected = NULL;
7277 selected = g_strdup(GST_ELEMENT_NAME(element));
7278 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7281 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7282 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7283 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7285 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7286 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7288 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7289 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7290 "max-video-width", player->adaptive_info.limit.width,
7291 "max-video-height", player->adaptive_info.limit.height, NULL);
7293 } else if (g_strrstr(klass, "Demuxer")) {
7295 LOGD("plugged element is demuxer. take it");
7297 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7298 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7301 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7302 int surface_type = 0;
7304 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7307 // to support trust-zone only
7308 if (g_strrstr(factory_name, "asfdemux")) {
7309 LOGD("set file-location %s", player->profile.uri);
7310 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7311 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7312 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7313 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7314 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7315 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7316 (__mmplayer_is_only_mp3_type(player->type))) {
7317 LOGD("[mpegaudioparse] set streaming pull mode.");
7318 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7320 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7321 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7324 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7325 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7326 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7328 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7329 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7331 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7332 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7333 (MMPLAYER_IS_DASH_STREAMING(player))) {
7334 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7335 _mm_player_streaming_set_multiqueue(player->streamer, element);
7336 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7345 __mmplayer_release_misc(mmplayer_t *player)
7348 bool cur_mode = player->set_mode.rich_audio;
7351 MMPLAYER_RETURN_IF_FAIL(player);
7353 player->video_decoded_cb = NULL;
7354 player->video_decoded_cb_user_param = NULL;
7355 player->video_stream_prerolled = false;
7357 player->audio_decoded_cb = NULL;
7358 player->audio_decoded_cb_user_param = NULL;
7359 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7361 player->audio_stream_changed_cb = NULL;
7362 player->audio_stream_changed_cb_user_param = NULL;
7364 player->sent_bos = FALSE;
7365 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7367 player->seek_state = MMPLAYER_SEEK_NONE;
7369 player->total_bitrate = 0;
7370 player->total_maximum_bitrate = 0;
7372 player->not_found_demuxer = 0;
7374 player->last_position = 0;
7375 player->duration = 0;
7376 player->http_content_size = 0;
7377 player->not_supported_codec = MISSING_PLUGIN_NONE;
7378 player->can_support_codec = FOUND_PLUGIN_NONE;
7379 player->pending_seek.is_pending = false;
7380 player->pending_seek.pos = 0;
7381 player->msg_posted = FALSE;
7382 player->has_many_types = FALSE;
7383 player->is_subtitle_force_drop = FALSE;
7384 player->play_subtitle = FALSE;
7385 player->adjust_subtitle_pos = 0;
7386 player->has_closed_caption = FALSE;
7387 player->set_mode.video_export = false;
7388 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7389 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7391 player->set_mode.rich_audio = cur_mode;
7393 if (player->audio_device_cb_id > 0 &&
7394 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7395 LOGW("failed to remove audio device_connected_callback");
7396 player->audio_device_cb_id = 0;
7398 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7399 player->bitrate[i] = 0;
7400 player->maximum_bitrate[i] = 0;
7403 /* free memory related to audio effect */
7404 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7406 if (player->adaptive_info.var_list) {
7407 g_list_free_full(player->adaptive_info.var_list, g_free);
7408 player->adaptive_info.var_list = NULL;
7411 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7412 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7413 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7415 /* Reset video360 settings to their defaults in case if the pipeline is to be
7418 player->video360_metadata.is_spherical = -1;
7419 player->is_openal_plugin_used = FALSE;
7421 player->is_content_spherical = FALSE;
7422 player->is_video360_enabled = TRUE;
7423 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7424 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7425 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7426 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7427 player->video360_zoom = 1.0f;
7428 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7429 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7431 player->sound.rg_enable = false;
7433 __mmplayer_initialize_video_roi(player);
7438 __mmplayer_release_misc_post(mmplayer_t *player)
7440 char *original_uri = NULL;
7443 /* player->pipeline is already released before. */
7445 MMPLAYER_RETURN_IF_FAIL(player);
7447 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7449 /* clean found audio decoders */
7450 if (player->audio_decoders) {
7451 GList *a_dec = player->audio_decoders;
7452 for (; a_dec; a_dec = g_list_next(a_dec)) {
7453 gchar *name = a_dec->data;
7454 MMPLAYER_FREEIF(name);
7456 g_list_free(player->audio_decoders);
7457 player->audio_decoders = NULL;
7460 /* clean the uri list except original uri */
7461 if (player->uri_info.uri_list) {
7462 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7464 if (player->attrs) {
7465 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7466 LOGD("restore original uri = %s", original_uri);
7468 if (mm_attrs_commit_all(player->attrs))
7469 LOGE("failed to commit the original uri.");
7472 GList *uri_list = player->uri_info.uri_list;
7473 for (; uri_list; uri_list = g_list_next(uri_list)) {
7474 gchar *uri = uri_list->data;
7475 MMPLAYER_FREEIF(uri);
7477 g_list_free(player->uri_info.uri_list);
7478 player->uri_info.uri_list = NULL;
7481 /* clear the audio stream buffer list */
7482 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7484 /* clear the video stream bo list */
7485 __mmplayer_video_stream_destroy_bo_list(player);
7486 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7488 if (player->profile.input_mem.buf) {
7489 free(player->profile.input_mem.buf);
7490 player->profile.input_mem.buf = NULL;
7492 player->profile.input_mem.len = 0;
7493 player->profile.input_mem.offset = 0;
7495 player->uri_info.uri_idx = 0;
7500 __mmplayer_check_subtitle(mmplayer_t *player)
7502 MMHandleType attrs = 0;
7503 char *subtitle_uri = NULL;
7507 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7509 /* get subtitle attribute */
7510 attrs = MMPLAYER_GET_ATTRS(player);
7514 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7515 if (!subtitle_uri || !strlen(subtitle_uri))
7518 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7519 player->is_external_subtitle_present = TRUE;
7527 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7529 MMPLAYER_RETURN_IF_FAIL(player);
7531 if (player->eos_timer) {
7532 LOGD("cancel eos timer");
7533 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7534 player->eos_timer = 0;
7541 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7545 MMPLAYER_RETURN_IF_FAIL(player);
7546 MMPLAYER_RETURN_IF_FAIL(sink);
7548 player->sink_elements = g_list_append(player->sink_elements, sink);
7554 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7558 MMPLAYER_RETURN_IF_FAIL(player);
7559 MMPLAYER_RETURN_IF_FAIL(sink);
7561 player->sink_elements = g_list_remove(player->sink_elements, sink);
7567 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7568 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7570 mmplayer_signal_item_t *item = NULL;
7573 MMPLAYER_RETURN_IF_FAIL(player);
7575 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7576 LOGE("invalid signal type [%d]", type);
7580 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7582 LOGE("cannot connect signal [%s]", signal);
7587 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7588 player->signals[type] = g_list_append(player->signals[type], item);
7594 /* NOTE : be careful with calling this api. please refer to below glib comment
7595 * glib comment : Note that there is a bug in GObject that makes this function much
7596 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7597 * will no longer be called, but, the signal handler is not currently disconnected.
7598 * If the instance is itself being freed at the same time than this doesn't matter,
7599 * since the signal will automatically be removed, but if instance persists,
7600 * then the signal handler will leak. You should not remove the signal yourself
7601 * because in a future versions of GObject, the handler will automatically be
7604 * It's possible to work around this problem in a way that will continue to work
7605 * with future versions of GObject by checking that the signal handler is still
7606 * connected before disconnected it:
7608 * if (g_signal_handler_is_connected(instance, id))
7609 * g_signal_handler_disconnect(instance, id);
7612 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7614 GList *sig_list = NULL;
7615 mmplayer_signal_item_t *item = NULL;
7619 MMPLAYER_RETURN_IF_FAIL(player);
7621 LOGD("release signals type : %d", type);
7623 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7624 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7625 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7626 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7627 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7628 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7632 sig_list = player->signals[type];
7634 for (; sig_list; sig_list = sig_list->next) {
7635 item = sig_list->data;
7637 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7638 if (g_signal_handler_is_connected(item->obj, item->sig))
7639 g_signal_handler_disconnect(item->obj, item->sig);
7642 MMPLAYER_FREEIF(item);
7645 g_list_free(player->signals[type]);
7646 player->signals[type] = NULL;
7654 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7656 mmplayer_t *player = 0;
7657 int prev_display_surface_type = 0;
7658 void *prev_display_overlay = NULL;
7662 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7663 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7665 player = MM_PLAYER_CAST(handle);
7667 /* check video sinkbin is created */
7668 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7669 LOGW("Videosink is already created");
7670 return MM_ERROR_NONE;
7673 LOGD("videosink element is not yet ready");
7675 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7676 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7678 return MM_ERROR_INVALID_ARGUMENT;
7681 /* load previous attributes */
7682 if (player->attrs) {
7683 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7684 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7685 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7686 if (prev_display_surface_type == surface_type) {
7687 LOGD("incoming display surface type is same as previous one, do nothing..");
7689 return MM_ERROR_NONE;
7692 LOGE("failed to load attributes");
7694 return MM_ERROR_PLAYER_INTERNAL;
7697 /* videobin is not created yet, so we just set attributes related to display surface */
7698 LOGD("store display attribute for given surface type(%d)", surface_type);
7699 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7700 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7701 if (mm_attrs_commit_all(player->attrs)) {
7702 LOGE("failed to commit attribute");
7704 return MM_ERROR_PLAYER_INTERNAL;
7708 return MM_ERROR_NONE;
7711 /* Note : if silent is true, then subtitle would not be displayed. :*/
7713 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7715 mmplayer_t *player = (mmplayer_t *)hplayer;
7719 /* check player handle */
7720 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7722 player->set_mode.subtitle_off = silent;
7724 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7728 return MM_ERROR_NONE;
7732 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7734 mmplayer_gst_element_t *mainbin = NULL;
7735 mmplayer_gst_element_t *textbin = NULL;
7736 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7737 GstState current_state = GST_STATE_VOID_PENDING;
7738 GstState element_state = GST_STATE_VOID_PENDING;
7739 GstState element_pending_state = GST_STATE_VOID_PENDING;
7741 GstEvent *event = NULL;
7742 int result = MM_ERROR_NONE;
7744 GstClock *curr_clock = NULL;
7745 GstClockTime base_time, start_time, curr_time;
7750 /* check player handle */
7751 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7753 player->pipeline->mainbin &&
7754 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7756 mainbin = player->pipeline->mainbin;
7757 textbin = player->pipeline->textbin;
7759 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7761 // sync clock with current pipeline
7762 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7763 curr_time = gst_clock_get_time(curr_clock);
7765 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7766 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7768 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7769 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7771 if (current_state > GST_STATE_READY) {
7772 // sync state with current pipeline
7773 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7774 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7775 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7777 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7778 if (GST_STATE_CHANGE_FAILURE == ret) {
7779 LOGE("fail to state change.");
7780 result = MM_ERROR_PLAYER_INTERNAL;
7784 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7785 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7788 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7789 gst_object_unref(curr_clock);
7792 // seek to current position
7793 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7794 result = MM_ERROR_PLAYER_INVALID_STATE;
7795 LOGE("gst_element_query_position failed, invalid state");
7799 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7800 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);
7802 _mmplayer_gst_send_event_to_sink(player, event);
7804 result = MM_ERROR_PLAYER_INTERNAL;
7805 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7809 /* sync state with current pipeline */
7810 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7811 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7812 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7814 return MM_ERROR_NONE;
7817 /* release text pipeline resource */
7818 player->textsink_linked = 0;
7820 /* release signal */
7821 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7823 /* release textbin with it's childs */
7824 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7825 MMPLAYER_FREEIF(player->pipeline->textbin);
7826 player->pipeline->textbin = NULL;
7828 /* release subtitle elem */
7829 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7830 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7836 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7838 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7839 GstState current_state = GST_STATE_VOID_PENDING;
7841 MMHandleType attrs = 0;
7842 mmplayer_gst_element_t *mainbin = NULL;
7843 mmplayer_gst_element_t *textbin = NULL;
7845 gchar *subtitle_uri = NULL;
7846 int result = MM_ERROR_NONE;
7847 const gchar *charset = NULL;
7851 /* check player handle */
7852 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7854 player->pipeline->mainbin &&
7855 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7856 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7858 mainbin = player->pipeline->mainbin;
7859 textbin = player->pipeline->textbin;
7861 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7862 if (current_state < GST_STATE_READY) {
7863 result = MM_ERROR_PLAYER_INVALID_STATE;
7864 LOGE("Pipeline is not in proper state");
7868 attrs = MMPLAYER_GET_ATTRS(player);
7870 LOGE("cannot get content attribute");
7871 result = MM_ERROR_PLAYER_INTERNAL;
7875 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7876 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7877 LOGE("subtitle uri is not proper filepath");
7878 result = MM_ERROR_PLAYER_INVALID_URI;
7882 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7883 LOGE("failed to get storage info of subtitle path");
7884 result = MM_ERROR_PLAYER_INVALID_URI;
7888 LOGD("old subtitle file path is [%s]", subtitle_uri);
7889 LOGD("new subtitle file path is [%s]", filepath);
7891 if (!strcmp(filepath, subtitle_uri)) {
7892 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7895 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7896 if (mm_attrs_commit_all(player->attrs)) {
7897 LOGE("failed to commit.");
7902 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7903 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7904 player->subtitle_language_list = NULL;
7905 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7907 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7908 if (ret != GST_STATE_CHANGE_SUCCESS) {
7909 LOGE("failed to change state of textbin to READY");
7910 result = MM_ERROR_PLAYER_INTERNAL;
7914 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7915 if (ret != GST_STATE_CHANGE_SUCCESS) {
7916 LOGE("failed to change state of subparse to READY");
7917 result = MM_ERROR_PLAYER_INTERNAL;
7921 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7922 if (ret != GST_STATE_CHANGE_SUCCESS) {
7923 LOGE("failed to change state of filesrc to READY");
7924 result = MM_ERROR_PLAYER_INTERNAL;
7928 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7930 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7932 charset = _mmplayer_get_charset(filepath);
7934 LOGD("detected charset is %s", charset);
7935 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7938 result = _mmplayer_sync_subtitle_pipeline(player);
7945 /* API to switch between external subtitles */
7947 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7949 int result = MM_ERROR_NONE;
7950 mmplayer_t *player = (mmplayer_t *)hplayer;
7955 /* check player handle */
7956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7958 /* filepath can be null in idle state */
7960 /* check file path */
7961 if ((path = strstr(filepath, "file://")))
7962 result = _mmplayer_exist_file_path(path + 7);
7964 result = _mmplayer_exist_file_path(filepath);
7966 if (result != MM_ERROR_NONE) {
7967 LOGE("invalid subtitle path 0x%X", result);
7968 return result; /* file not found or permission denied */
7972 if (!player->pipeline) {
7974 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7975 if (mm_attrs_commit_all(player->attrs)) {
7976 LOGE("failed to commit"); /* subtitle path will not be created */
7977 return MM_ERROR_PLAYER_INTERNAL;
7980 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7981 /* check filepath */
7982 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7984 if (!__mmplayer_check_subtitle(player)) {
7985 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7986 if (mm_attrs_commit_all(player->attrs)) {
7987 LOGE("failed to commit");
7988 return MM_ERROR_PLAYER_INTERNAL;
7991 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7992 LOGE("fail to create text pipeline");
7993 return MM_ERROR_PLAYER_INTERNAL;
7996 result = _mmplayer_sync_subtitle_pipeline(player);
7998 result = __mmplayer_change_external_subtitle_language(player, filepath);
8001 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8002 player->is_external_subtitle_added_now = TRUE;
8004 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8005 if (!player->subtitle_language_list) {
8006 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8007 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8008 LOGW("subtitle language list is not updated yet");
8010 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8018 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8020 int result = MM_ERROR_NONE;
8021 gchar *change_pad_name = NULL;
8022 GstPad *sinkpad = NULL;
8023 mmplayer_gst_element_t *mainbin = NULL;
8024 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8025 GstCaps *caps = NULL;
8026 gint total_track_num = 0;
8030 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8031 MM_ERROR_PLAYER_NOT_INITIALIZED);
8033 LOGD("Change Track(%d) to %d", type, index);
8035 mainbin = player->pipeline->mainbin;
8037 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8038 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8039 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8040 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8042 /* Changing Video Track is not supported. */
8043 LOGE("Track Type Error");
8047 if (mainbin[elem_idx].gst == NULL) {
8048 result = MM_ERROR_PLAYER_NO_OP;
8049 LOGD("Req track doesn't exist");
8053 total_track_num = player->selector[type].total_track_num;
8054 if (total_track_num <= 0) {
8055 result = MM_ERROR_PLAYER_NO_OP;
8056 LOGD("Language list is not available");
8060 if ((index < 0) || (index >= total_track_num)) {
8061 result = MM_ERROR_INVALID_ARGUMENT;
8062 LOGD("Not a proper index : %d", index);
8066 /*To get the new pad from the selector*/
8067 change_pad_name = g_strdup_printf("sink_%u", index);
8068 if (change_pad_name == NULL) {
8069 result = MM_ERROR_PLAYER_INTERNAL;
8070 LOGD("Pad does not exists");
8074 LOGD("new active pad name: %s", change_pad_name);
8076 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8077 if (sinkpad == NULL) {
8078 LOGD("sinkpad is NULL");
8079 result = MM_ERROR_PLAYER_INTERNAL;
8083 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8084 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8086 caps = gst_pad_get_current_caps(sinkpad);
8087 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8090 gst_object_unref(sinkpad);
8092 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8093 __mmplayer_set_audio_attrs(player, caps);
8096 MMPLAYER_FREEIF(change_pad_name);
8101 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8103 int result = MM_ERROR_NONE;
8104 mmplayer_t *player = NULL;
8105 mmplayer_gst_element_t *mainbin = NULL;
8107 gint current_active_index = 0;
8109 GstState current_state = GST_STATE_VOID_PENDING;
8110 GstEvent *event = NULL;
8115 player = (mmplayer_t *)hplayer;
8116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8118 if (!player->pipeline) {
8119 LOGE("Track %d pre setting -> %d", type, index);
8121 player->selector[type].active_pad_index = index;
8125 mainbin = player->pipeline->mainbin;
8127 current_active_index = player->selector[type].active_pad_index;
8129 /*If index is same as running index no need to change the pad*/
8130 if (current_active_index == index)
8133 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8134 result = MM_ERROR_PLAYER_INVALID_STATE;
8138 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8139 if (current_state < GST_STATE_PAUSED) {
8140 result = MM_ERROR_PLAYER_INVALID_STATE;
8141 LOGW("Pipeline not in porper state");
8145 result = __mmplayer_change_selector_pad(player, type, index);
8146 if (result != MM_ERROR_NONE) {
8147 LOGE("change selector pad error");
8151 player->selector[type].active_pad_index = index;
8153 if (current_state == GST_STATE_PLAYING) {
8154 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8155 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8156 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8158 _mmplayer_gst_send_event_to_sink(player, event);
8160 result = MM_ERROR_PLAYER_INTERNAL;
8170 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8172 mmplayer_t *player = (mmplayer_t *)hplayer;
8176 /* check player handle */
8177 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8179 *silent = player->set_mode.subtitle_off;
8181 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8185 return MM_ERROR_NONE;
8189 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8191 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8192 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8194 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8195 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8199 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8200 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8201 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8202 mmplayer_dump_t *dump_s;
8203 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8204 if (dump_s == NULL) {
8205 LOGE("malloc fail");
8209 dump_s->dump_element_file = NULL;
8210 dump_s->dump_pad = NULL;
8211 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8213 if (dump_s->dump_pad) {
8214 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8215 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]);
8216 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8217 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);
8218 /* add list for removed buffer probe and close FILE */
8219 player->dump_list = g_list_append(player->dump_list, dump_s);
8220 LOGD("%s sink pad added buffer probe for dump", factory_name);
8223 MMPLAYER_FREEIF(dump_s);
8224 LOGE("failed to get %s sink pad added", factory_name);
8231 static GstPadProbeReturn
8232 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8234 FILE *dump_data = (FILE *)u_data;
8236 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8237 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8239 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8241 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8243 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8245 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8247 gst_buffer_unmap(buffer, &probe_info);
8249 return GST_PAD_PROBE_OK;
8253 __mmplayer_release_dump_list(GList *dump_list)
8255 GList *d_list = dump_list;
8260 for (; d_list; d_list = g_list_next(d_list)) {
8261 mmplayer_dump_t *dump_s = d_list->data;
8262 if (dump_s->dump_pad) {
8263 if (dump_s->probe_handle_id)
8264 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8265 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8267 if (dump_s->dump_element_file) {
8268 fclose(dump_s->dump_element_file);
8269 dump_s->dump_element_file = NULL;
8271 MMPLAYER_FREEIF(dump_s);
8273 g_list_free(dump_list);
8278 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8280 mmplayer_t *player = (mmplayer_t *)hplayer;
8284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8285 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8287 *exist = (bool)player->has_closed_caption;
8291 return MM_ERROR_NONE;
8295 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8300 LOGD("unref internal gst buffer %p", buffer);
8302 gst_buffer_unref((GstBuffer *)buffer);
8309 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8311 mmplayer_t *player = (mmplayer_t *)hplayer;
8315 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8316 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8318 if (MMPLAYER_IS_STREAMING(player))
8319 *timeout = (int)player->ini.live_state_change_timeout;
8321 *timeout = (int)player->ini.localplayback_state_change_timeout;
8323 LOGD("timeout = %d", *timeout);
8326 return MM_ERROR_NONE;
8330 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8334 MMPLAYER_RETURN_IF_FAIL(player);
8336 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8338 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8339 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8340 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8341 player->storage_info[i].id = -1;
8342 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8344 if (path_type != MMPLAYER_PATH_MAX)
8353 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8355 int ret = MM_ERROR_NONE;
8356 mmplayer_t *player = (mmplayer_t *)hplayer;
8357 MMMessageParamType msg_param = {0, };
8360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8362 LOGW("state changed storage %d:%d", id, state);
8364 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8365 return MM_ERROR_NONE;
8367 /* FIXME: text path should be handled seperately. */
8368 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8369 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8370 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8371 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8372 LOGW("external storage is removed");
8374 if (player->msg_posted == FALSE) {
8375 memset(&msg_param, 0, sizeof(MMMessageParamType));
8376 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8377 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8378 player->msg_posted = TRUE;
8381 /* unrealize the player */
8382 ret = _mmplayer_unrealize(hplayer);
8383 if (ret != MM_ERROR_NONE)
8384 LOGE("failed to unrealize");
8392 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8394 int ret = MM_ERROR_NONE;
8395 mmplayer_t *player = (mmplayer_t *)hplayer;
8396 int idx = 0, total = 0;
8397 gchar *result = NULL, *tmp = NULL;
8400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8401 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8403 total = *num = g_list_length(player->adaptive_info.var_list);
8405 LOGW("There is no stream variant info.");
8409 result = g_strdup("");
8410 for (idx = 0 ; idx < total ; idx++) {
8411 stream_variant_t *v_data = NULL;
8412 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8415 gchar data[64] = {0};
8416 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8418 tmp = g_strconcat(result, data, NULL);
8422 LOGW("There is no variant data in %d", idx);
8427 *var_info = (char *)result;
8429 LOGD("variant info %d:%s", *num, *var_info);
8435 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8437 int ret = MM_ERROR_NONE;
8438 mmplayer_t *player = (mmplayer_t *)hplayer;
8441 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8443 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8445 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8446 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8447 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8449 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8450 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8451 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8452 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8454 /* FIXME: seek to current position for applying new variant limitation */
8463 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8465 int ret = MM_ERROR_NONE;
8466 mmplayer_t *player = (mmplayer_t *)hplayer;
8469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8470 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8472 *bandwidth = player->adaptive_info.limit.bandwidth;
8473 *width = player->adaptive_info.limit.width;
8474 *height = player->adaptive_info.limit.height;
8476 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8483 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8485 int ret = MM_ERROR_NONE;
8486 mmplayer_t *player = (mmplayer_t *)hplayer;
8489 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8490 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8491 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8493 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8495 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8496 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8497 else /* live case */
8498 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8500 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8507 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8509 #define IDX_FIRST_SW_CODEC 0
8510 mmplayer_t *player = (mmplayer_t *)hplayer;
8511 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8512 MMHandleType attrs = 0;
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8517 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8518 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8519 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8521 switch (stream_type) {
8522 case MM_PLAYER_STREAM_TYPE_AUDIO:
8523 /* to support audio codec selection, codec info have to be added in ini file as below.
8524 audio codec element hw = xxxx
8525 audio codec element sw = avdec */
8526 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8527 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8528 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8529 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8530 LOGE("There is no audio codec info for codec_type %d", codec_type);
8531 return MM_ERROR_PLAYER_NO_OP;
8534 case MM_PLAYER_STREAM_TYPE_VIDEO:
8535 /* to support video codec selection, codec info have to be added in ini file as below.
8536 video codec element hw = omx
8537 video codec element sw = avdec */
8538 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8539 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8540 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8541 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8542 LOGE("There is no video codec info for codec_type %d", codec_type);
8543 return MM_ERROR_PLAYER_NO_OP;
8547 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8548 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8552 LOGD("update %s codec_type to %d", attr_name, codec_type);
8554 attrs = MMPLAYER_GET_ATTRS(player);
8555 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8557 if (mm_attrs_commit_all(player->attrs)) {
8558 LOGE("failed to commit codec_type attributes");
8559 return MM_ERROR_PLAYER_INTERNAL;
8563 return MM_ERROR_NONE;
8567 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8569 mmplayer_t *player = (mmplayer_t *)hplayer;
8570 GstElement *rg_vol_element = NULL;
8574 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8576 player->sound.rg_enable = enabled;
8578 /* just hold rgvolume enable value if pipeline is not ready */
8579 if (!player->pipeline || !player->pipeline->audiobin) {
8580 LOGD("pipeline is not ready. holding rgvolume enable value");
8581 return MM_ERROR_NONE;
8584 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8586 if (!rg_vol_element) {
8587 LOGD("rgvolume element is not created");
8588 return MM_ERROR_PLAYER_INTERNAL;
8592 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8594 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8598 return MM_ERROR_NONE;
8602 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8604 mmplayer_t *player = (mmplayer_t *)hplayer;
8605 GstElement *rg_vol_element = NULL;
8606 gboolean enable = FALSE;
8610 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8611 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8613 /* just hold enable_rg value if pipeline is not ready */
8614 if (!player->pipeline || !player->pipeline->audiobin) {
8615 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8616 *enabled = player->sound.rg_enable;
8617 return MM_ERROR_NONE;
8620 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8622 if (!rg_vol_element) {
8623 LOGD("rgvolume element is not created");
8624 return MM_ERROR_PLAYER_INTERNAL;
8627 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8628 *enabled = (bool)enable;
8632 return MM_ERROR_NONE;
8636 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8638 mmplayer_t *player = (mmplayer_t *)hplayer;
8639 MMHandleType attrs = 0;
8640 void *handle = NULL;
8641 int ret = MM_ERROR_NONE;
8645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8647 attrs = MMPLAYER_GET_ATTRS(player);
8648 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8650 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8652 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8653 return MM_ERROR_PLAYER_INTERNAL;
8656 player->video_roi.scale_x = scale_x;
8657 player->video_roi.scale_y = scale_y;
8658 player->video_roi.scale_width = scale_width;
8659 player->video_roi.scale_height = scale_height;
8661 /* check video sinkbin is created */
8662 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8663 return MM_ERROR_NONE;
8665 if (!gst_video_overlay_set_video_roi_area(
8666 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8667 scale_x, scale_y, scale_width, scale_height))
8668 ret = MM_ERROR_PLAYER_INTERNAL;
8670 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8671 scale_x, scale_y, scale_width, scale_height);
8679 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8681 mmplayer_t *player = (mmplayer_t *)hplayer;
8682 int ret = MM_ERROR_NONE;
8686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8687 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8689 *scale_x = player->video_roi.scale_x;
8690 *scale_y = player->video_roi.scale_y;
8691 *scale_width = player->video_roi.scale_width;
8692 *scale_height = player->video_roi.scale_height;
8694 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8695 *scale_x, *scale_y, *scale_width, *scale_height);
8701 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8703 mmplayer_t* player = (mmplayer_t*)hplayer;
8707 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8709 player->client_pid = pid;
8711 LOGD("client pid[%d] %p", pid, player);
8715 return MM_ERROR_NONE;
8719 __mmplayer_update_duration_value(mmplayer_t *player)
8721 gboolean ret = FALSE;
8722 gint64 dur_nsec = 0;
8723 LOGD("try to update duration");
8725 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8726 player->duration = dur_nsec;
8727 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8731 if (player->duration < 0) {
8732 LOGW("duration is Non-Initialized !!!");
8733 player->duration = 0;
8736 /* update streaming service type */
8737 player->streaming_type = _mmplayer_get_stream_service_type(player);
8739 /* check duration is OK */
8740 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8741 /* FIXIT : find another way to get duration here. */
8742 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8748 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8750 /* update audio params
8751 NOTE : We need original audio params and it can be only obtained from src pad of audio
8752 decoder. Below code only valid when we are not using 'resampler' just before
8753 'audioconverter'. */
8754 GstCaps *caps_a = NULL;
8756 gint samplerate = 0, channels = 0;
8757 GstStructure *p = NULL;
8758 GstElement *aconv = NULL;
8760 LOGD("try to update audio attrs");
8762 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8764 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8765 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8766 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8767 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8769 LOGE("there is no audio converter");
8773 pad = gst_element_get_static_pad(aconv, "sink");
8776 LOGW("failed to get pad from audio converter");
8780 caps_a = gst_pad_get_current_caps(pad);
8782 LOGW("not ready to get audio caps");
8783 gst_object_unref(pad);
8787 p = gst_caps_get_structure(caps_a, 0);
8789 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8791 gst_structure_get_int(p, "rate", &samplerate);
8792 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8794 gst_structure_get_int(p, "channels", &channels);
8795 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8797 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8799 gst_caps_unref(caps_a);
8800 gst_object_unref(pad);
8806 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8808 LOGD("try to update video attrs");
8810 GstCaps *caps_v = NULL;
8814 GstStructure *p = NULL;
8816 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8817 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8819 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8821 LOGD("no videosink sink pad");
8825 caps_v = gst_pad_get_current_caps(pad);
8826 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8827 if (!caps_v && player->v_stream_caps) {
8828 caps_v = player->v_stream_caps;
8829 gst_caps_ref(caps_v);
8833 LOGD("no negitiated caps from videosink");
8834 gst_object_unref(pad);
8838 p = gst_caps_get_structure(caps_v, 0);
8839 gst_structure_get_int(p, "width", &width);
8840 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8842 gst_structure_get_int(p, "height", &height);
8843 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8845 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8847 SECURE_LOGD("width : %d height : %d", width, height);
8849 gst_caps_unref(caps_v);
8850 gst_object_unref(pad);
8853 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8854 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8861 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8863 gboolean ret = FALSE;
8864 guint64 data_size = 0;
8868 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8869 if (!player->duration)
8872 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8873 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8874 if (stat(path, &sb) == 0)
8875 data_size = (guint64)sb.st_size;
8877 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8878 data_size = player->http_content_size;
8881 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8884 guint64 bitrate = 0;
8885 guint64 msec_dur = 0;
8887 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8889 bitrate = data_size * 8 * 1000 / msec_dur;
8890 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8891 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8895 LOGD("player duration is less than 0");
8899 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8900 if (player->total_bitrate) {
8901 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8910 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8912 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8913 data->uri_type = uri_type;
8917 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8919 int ret = MM_ERROR_PLAYER_INVALID_URI;
8921 char *buffer = NULL;
8922 char *seperator = strchr(path, ',');
8923 char ext[100] = {0,}, size[100] = {0,};
8926 if ((buffer = strstr(path, "ext="))) {
8927 buffer += strlen("ext=");
8929 if (strlen(buffer)) {
8930 strncpy(ext, buffer, 99);
8932 if ((seperator = strchr(ext, ','))
8933 || (seperator = strchr(ext, ' '))
8934 || (seperator = strchr(ext, '\0'))) {
8935 seperator[0] = '\0';
8940 if ((buffer = strstr(path, "size="))) {
8941 buffer += strlen("size=");
8943 if (strlen(buffer) > 0) {
8944 strncpy(size, buffer, 99);
8946 if ((seperator = strchr(size, ','))
8947 || (seperator = strchr(size, ' '))
8948 || (seperator = strchr(size, '\0'))) {
8949 seperator[0] = '\0';
8952 mem_size = atoi(size);
8957 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8959 if (mem_size && param) {
8960 if (data->input_mem.buf)
8961 free(data->input_mem.buf);
8962 data->input_mem.buf = malloc(mem_size);
8964 if (data->input_mem.buf) {
8965 memcpy(data->input_mem.buf, param, mem_size);
8966 data->input_mem.len = mem_size;
8967 ret = MM_ERROR_NONE;
8969 LOGE("failed to alloc mem %d", mem_size);
8970 ret = MM_ERROR_PLAYER_INTERNAL;
8973 data->input_mem.offset = 0;
8974 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8981 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8983 gchar *location = NULL;
8986 int ret = MM_ERROR_NONE;
8988 if ((path = strstr(uri, "file://"))) {
8989 location = g_filename_from_uri(uri, NULL, &err);
8990 if (!location || (err != NULL)) {
8991 LOGE("Invalid URI '%s' for filesrc: %s", path,
8992 (err != NULL) ? err->message : "unknown error");
8996 MMPLAYER_FREEIF(location);
8998 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8999 return MM_ERROR_PLAYER_INVALID_URI;
9001 LOGD("path from uri: %s", location);
9004 path = (location != NULL) ? (location) : ((char *)uri);
9007 ret = _mmplayer_exist_file_path(path);
9009 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9010 if (ret == MM_ERROR_NONE) {
9011 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9012 if (_mmplayer_is_sdp_file(path)) {
9013 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9014 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9016 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9018 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9019 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9021 LOGE("invalid uri, could not play..");
9022 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9025 MMPLAYER_FREEIF(location);
9030 static mmplayer_video_decoded_data_info_t *
9031 __mmplayer_create_stream_from_pad(GstPad *pad)
9033 GstCaps *caps = NULL;
9034 GstStructure *structure = NULL;
9035 unsigned int fourcc = 0;
9036 const gchar *string_format = NULL;
9037 mmplayer_video_decoded_data_info_t *stream = NULL;
9039 MMPixelFormatType format;
9042 caps = gst_pad_get_current_caps(pad);
9044 LOGE("Caps is NULL.");
9049 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9051 structure = gst_caps_get_structure(caps, 0);
9052 gst_structure_get_int(structure, "width", &width);
9053 gst_structure_get_int(structure, "height", &height);
9054 string_format = gst_structure_get_string(structure, "format");
9057 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9058 format = _mmplayer_get_pixtype(fourcc);
9059 gst_video_info_from_caps(&info, caps);
9060 gst_caps_unref(caps);
9063 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9064 LOGE("Wrong condition!!");
9068 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9070 LOGE("failed to alloc mem for video data");
9074 stream->width = width;
9075 stream->height = height;
9076 stream->format = format;
9077 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9083 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9085 unsigned int pitch = 0;
9086 unsigned int size = 0;
9088 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9091 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9092 bo = gst_tizen_memory_get_bos(mem, index);
9094 stream->bo[index] = tbm_bo_ref(bo);
9096 LOGE("failed to get bo for index %d", index);
9099 for (index = 0; index < stream->plane_num; index++) {
9100 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9101 stream->stride[index] = pitch;
9103 stream->elevation[index] = size / pitch;
9105 stream->elevation[index] = stream->height;
9110 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9112 if (stream->format == MM_PIXEL_FORMAT_I420) {
9113 int ret = TBM_SURFACE_ERROR_NONE;
9114 tbm_surface_h surface;
9115 tbm_surface_info_s info;
9117 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9119 ret = tbm_surface_get_info(surface, &info);
9120 if (ret != TBM_SURFACE_ERROR_NONE) {
9121 tbm_surface_destroy(surface);
9125 tbm_surface_destroy(surface);
9126 stream->stride[0] = info.planes[0].stride;
9127 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9128 stream->stride[1] = info.planes[1].stride;
9129 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9130 stream->stride[2] = info.planes[2].stride;
9131 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9132 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9133 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9134 stream->stride[0] = stream->width * 4;
9135 stream->elevation[0] = stream->height;
9136 stream->bo_size = stream->stride[0] * stream->height;
9138 LOGE("Not support format %d", stream->format);
9146 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9148 tbm_bo_handle thandle;
9150 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9151 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9152 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9156 unsigned char *src = NULL;
9157 unsigned char *dest = NULL;
9158 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9160 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9162 LOGE("fail to gst_memory_map");
9166 if (!mapinfo.data) {
9167 LOGE("data pointer is wrong");
9171 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9172 if (!stream->bo[0]) {
9173 LOGE("Fail to tbm_bo_alloc!!");
9177 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9179 LOGE("thandle pointer is wrong");
9183 if (stream->format == MM_PIXEL_FORMAT_I420) {
9184 src_stride[0] = GST_ROUND_UP_4(stream->width);
9185 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9186 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9187 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9190 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9191 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9193 for (i = 0; i < 3; i++) {
9194 src = mapinfo.data + src_offset[i];
9195 dest = thandle.ptr + dest_offset[i];
9200 for (j = 0; j < stream->height >> k; j++) {
9201 memcpy(dest, src, stream->width>>k);
9202 src += src_stride[i];
9203 dest += stream->stride[i];
9206 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9207 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9209 LOGE("Not support format %d", stream->format);
9213 tbm_bo_unmap(stream->bo[0]);
9214 gst_memory_unmap(mem, &mapinfo);
9220 tbm_bo_unmap(stream->bo[0]);
9223 gst_memory_unmap(mem, &mapinfo);
9229 __mmplayer_set_pause_state(mmplayer_t *player)
9231 if (player->sent_bos)
9234 /* rtsp case, get content attrs by GstMessage */
9235 if (MMPLAYER_IS_RTSP_STREAMING(player))
9238 /* it's first time to update all content attrs. */
9239 _mmplayer_update_content_attrs(player, ATTR_ALL);
9243 __mmplayer_set_playing_state(mmplayer_t *player)
9245 gchar *audio_codec = NULL;
9247 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9248 /* initialize because auto resume is done well. */
9249 player->resumed_by_rewind = FALSE;
9250 player->playback_rate = 1.0;
9253 if (player->sent_bos)
9256 /* try to get content metadata */
9258 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9259 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9260 * legacy mmfw-player api
9262 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9264 if ((player->cmd == MMPLAYER_COMMAND_START)
9265 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9266 __mmplayer_handle_missed_plugin(player);
9269 /* check audio codec field is set or not
9270 * we can get it from typefinder or codec's caps.
9272 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9274 /* The codec format can't be sent for audio only case like amr, mid etc.
9275 * Because, parser don't make related TAG.
9276 * So, if it's not set yet, fill it with found data.
9279 if (g_strrstr(player->type, "audio/midi"))
9280 audio_codec = "MIDI";
9281 else if (g_strrstr(player->type, "audio/x-amr"))
9282 audio_codec = "AMR";
9283 else if (g_strrstr(player->type, "audio/mpeg")
9284 && !g_strrstr(player->type, "mpegversion=(int)1"))
9285 audio_codec = "AAC";
9287 audio_codec = "unknown";
9289 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9291 if (mm_attrs_commit_all(player->attrs))
9292 LOGE("failed to update attributes");
9294 LOGD("set audio codec type with caps");