4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
160 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
162 static gpointer __mmplayer_gapless_play_thread(gpointer data);
163 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
164 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_release_dump_list(GList *dump_list);
166 static int __mmplayer_gst_realize(mmplayer_t *player);
167 static int __mmplayer_gst_unrealize(mmplayer_t *player);
168 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
169 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
172 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
173 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
174 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
175 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
176 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
177 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
178 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
179 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
180 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
181 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
182 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
183 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
188 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
189 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
192 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
193 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
194 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196 static void __mmplayer_set_pause_state(mmplayer_t *player);
197 static void __mmplayer_set_playing_state(mmplayer_t *player);
198 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
199 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to application by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incoming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 LOGD("commit [%d type] resource", type);
588 rm_ret = mm_resource_manager_commit(player->resource_manager);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
595 return MM_ERROR_NONE;
598 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 MMPLAYER_RETURN_IF_FAIL(player);
603 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
605 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
606 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
607 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
611 rm_ret = mm_resource_manager_commit(player->resource_manager);
612 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
613 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
616 /* de-initialize resource manager */
617 rm_ret = mm_resource_manager_destroy(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
623 player->resource_manager = NULL;
625 LOGD("resource manager is destroyed");
628 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
630 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
634 if (player->hw_resource[type] == NULL) {
635 LOGD("there is no acquired [%d type] resource", type);
636 return MM_ERROR_NONE;
639 LOGD("mark for release [%d type] resource", type);
640 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
641 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
643 return MM_ERROR_PLAYER_INTERNAL;
646 player->hw_resource[type] = NULL;
648 LOGD("commit [%d type] resource", type);
649 rm_ret = mm_resource_manager_commit(player->resource_manager);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
656 return MM_ERROR_NONE;
660 __mmplayer_initialize_gapless_play(mmplayer_t *player)
666 player->smooth_streaming = FALSE;
667 player->videodec_linked = 0;
668 player->audiodec_linked = 0;
669 player->textsink_linked = 0;
670 player->is_external_subtitle_present = FALSE;
671 player->is_external_subtitle_added_now = FALSE;
672 player->not_supported_codec = MISSING_PLUGIN_NONE;
673 player->can_support_codec = FOUND_PLUGIN_NONE;
674 player->pending_seek.is_pending = false;
675 player->pending_seek.pos = 0;
676 player->msg_posted = FALSE;
677 player->has_many_types = FALSE;
678 player->no_more_pad = FALSE;
679 player->not_found_demuxer = 0;
680 player->seek_state = MMPLAYER_SEEK_NONE;
681 player->is_subtitle_force_drop = FALSE;
682 player->play_subtitle = FALSE;
683 player->adjust_subtitle_pos = 0;
685 player->total_bitrate = 0;
686 player->total_maximum_bitrate = 0;
688 _mmplayer_track_initialize(player);
689 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
691 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
692 player->bitrate[i] = 0;
693 player->maximum_bitrate[i] = 0;
696 if (player->v_stream_caps) {
697 gst_caps_unref(player->v_stream_caps);
698 player->v_stream_caps = NULL;
701 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
703 /* clean found audio decoders */
704 if (player->audio_decoders) {
705 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
706 player->audio_decoders = NULL;
709 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
714 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
716 LOGI("set pipeline reconfigure state %d", state);
717 MMPLAYER_RECONFIGURE_LOCK(player);
718 player->gapless.reconfigure = state;
719 if (!state) /* wake up the waiting job */
720 MMPLAYER_RECONFIGURE_SIGNAL(player);
721 MMPLAYER_RECONFIGURE_UNLOCK(player);
725 __mmplayer_gapless_play_thread(gpointer data)
727 mmplayer_t *player = (mmplayer_t *)data;
728 mmplayer_gst_element_t *mainbin = NULL;
730 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
732 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
733 while (!player->gapless_play_thread_exit) {
734 LOGD("gapless play thread started. waiting for signal.");
735 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
737 LOGD("reconfigure pipeline for gapless play.");
739 if (player->gapless_play_thread_exit) {
740 _mmplayer_set_reconfigure_state(player, FALSE);
741 LOGD("exiting gapless play thread");
745 mainbin = player->pipeline->mainbin;
747 if (MMPLAYER_USE_DECODEBIN(player)) {
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
754 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
755 mainbin[MMPLAYER_M_SRC].gst = NULL;
758 /* Initialize Player values */
759 __mmplayer_initialize_gapless_play(player);
761 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
763 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
769 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
771 GSource *source = NULL;
775 source = g_main_context_find_source_by_id(context, source_id);
776 if (source != NULL) {
777 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
778 g_source_destroy(source);
785 _mmplayer_watcher_removed_notify(gpointer data)
787 mmplayer_t *player = (mmplayer_t *)data;
788 MMPLAYER_RETURN_IF_FAIL(player);
790 MMPLAYER_BUS_WATCHER_LOCK(player);
791 player->bus_watcher = 0;
792 MMPLAYER_BUS_WATCHER_SIGNAL(player);
793 MMPLAYER_BUS_WATCHER_UNLOCK(player);
797 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
799 mmplayer_t *player = (mmplayer_t *)hplayer;
802 MMPLAYER_RETURN_IF_FAIL(player);
804 /* disconnecting bus watch */
805 if (player->bus_watcher > 0) {
806 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
807 MMPLAYER_BUS_WATCHER_LOCK(player);
808 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
809 while (player->bus_watcher > 0) {
810 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
811 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
812 player->bus_watcher);
816 MMPLAYER_BUS_WATCHER_UNLOCK(player);
817 g_mutex_clear(&player->bus_watcher_mutex);
818 g_cond_clear(&player->bus_watcher_cond);
825 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
827 mmplayer_t *player = (mmplayer_t *)hplayer;
828 GstMessage *msg = NULL;
829 GQueue *queue = NULL;
832 MMPLAYER_RETURN_IF_FAIL(player);
834 /* destroy the gst bus msg thread */
835 if (player->bus_msg_thread) {
836 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
837 player->bus_msg_thread_exit = TRUE;
838 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
839 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
841 LOGD("gst bus msg thread exit.");
842 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
843 player->bus_msg_thread = NULL;
845 g_mutex_clear(&player->bus_msg_thread_mutex);
846 g_cond_clear(&player->bus_msg_thread_cond);
849 g_mutex_lock(&player->bus_msg_q_lock);
850 queue = player->bus_msg_q;
851 while (!g_queue_is_empty(queue)) {
852 msg = (GstMessage *)g_queue_pop_head(queue);
857 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
858 gst_message_unref(msg);
860 g_mutex_unlock(&player->bus_msg_q_lock);
866 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
868 GstElement *parent = NULL;
870 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
871 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
874 MMPLAYER_FSINK_LOCK(player);
876 /* get parent of fakesink */
877 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
879 LOGD("fakesink already removed");
883 gst_element_set_locked_state(fakesink->gst, TRUE);
885 /* setting the state to NULL never returns async
886 * so no need to wait for completion of state transition
888 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
889 LOGE("fakesink state change failure!");
890 /* FIXIT : should I return here? or try to proceed to next? */
893 /* remove fakesink from it's parent */
894 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
895 LOGE("failed to remove fakesink");
897 gst_object_unref(parent);
902 gst_object_unref(parent);
904 LOGD("state-holder removed");
906 gst_element_set_locked_state(fakesink->gst, FALSE);
908 MMPLAYER_FSINK_UNLOCK(player);
913 gst_element_set_locked_state(fakesink->gst, FALSE);
915 MMPLAYER_FSINK_UNLOCK(player);
919 static GstPadProbeReturn
920 __mmplayer_gst_combiner_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
922 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
923 return GST_PAD_PROBE_OK;
927 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
929 gint64 stop_running_time = 0;
930 gint64 position_running_time = 0;
934 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
935 if ((player->gapless.update_segment[idx] == TRUE) ||
936 !(player->track[idx].event_probe_id)) {
938 LOGW("[%d] skip", idx);
943 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
947 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
949 gst_segment_to_running_time(&player->gapless.segment[idx],
950 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
952 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
954 gst_segment_to_running_time(&player->gapless.segment[idx],
955 GST_FORMAT_TIME, player->duration);
958 position_running_time =
959 gst_segment_to_running_time(&player->gapless.segment[idx],
960 GST_FORMAT_TIME, player->gapless.segment[idx].position);
962 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
963 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
965 GST_TIME_ARGS(stop_running_time),
966 GST_TIME_ARGS(position_running_time),
967 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
970 position_running_time = MAX(position_running_time, stop_running_time);
971 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
972 GST_FORMAT_TIME, player->gapless.segment[idx].start);
973 position_running_time = MAX(0, position_running_time);
974 position = MAX(position, position_running_time);
978 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
979 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
980 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
982 player->gapless.start_time[stream_type] += position;
988 static GstPadProbeReturn
989 __mmplayer_gst_combiner_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
991 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
992 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
993 mmplayer_t *player = (mmplayer_t *)data;
994 GstCaps *caps = NULL;
995 GstStructure *str = NULL;
996 const gchar *name = NULL;
997 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
998 gboolean caps_ret = TRUE;
1000 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1001 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1002 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1007 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1009 GstStream *stream = NULL;
1011 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START)
1014 gst_event_parse_stream (event, &stream);
1015 if (stream == NULL) {
1016 LOGW ("Got a STREAM_START event without a GstStream");
1020 name = gst_stream_type_get_name(gst_stream_get_stream_type(stream));
1021 gst_object_unref (stream);
1027 if (strstr(name, "audio")) {
1028 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1029 } else if (strstr(name, "video")) {
1030 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1032 /* text track is not supportable */
1033 LOGE("invalid name %s", name);
1037 switch (GST_EVENT_TYPE(event)) {
1040 /* in case of gapless, drop eos event not to send it to sink */
1041 if (player->gapless.reconfigure && !player->msg_posted) {
1042 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1043 ret = GST_PAD_PROBE_DROP;
1047 case GST_EVENT_STREAM_START:
1049 __mmplayer_gst_selector_update_start_time(player, stream_type);
1052 case GST_EVENT_FLUSH_STOP:
1054 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1055 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1056 player->gapless.start_time[stream_type] = 0;
1059 case GST_EVENT_SEGMENT:
1064 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1065 gst_event_copy_segment(event, &segment);
1067 if (segment.format != GST_FORMAT_TIME)
1070 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1071 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1072 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1073 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1074 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1075 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1077 /* keep the all the segment ev to cover the seeking */
1078 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1079 player->gapless.update_segment[stream_type] = TRUE;
1081 if (!player->gapless.running)
1084 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1086 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1088 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1089 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1090 gst_event_unref(event);
1091 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1097 gdouble proportion = 0.0;
1098 GstClockTimeDiff diff = 0;
1099 GstClockTime timestamp = 0;
1100 gint64 running_time_diff = -1;
1101 GstQOSType type = 0;
1102 GstEvent *tmpev = NULL;
1104 running_time_diff = player->gapless.segment[stream_type].base;
1106 if (running_time_diff <= 0) /* don't need to adjust */
1109 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1110 gst_event_unref(event);
1112 if (timestamp < running_time_diff) {
1113 LOGW("QOS event from previous group");
1114 ret = GST_PAD_PROBE_DROP;
1119 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1120 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1121 stream_type, GST_TIME_ARGS(timestamp),
1122 GST_TIME_ARGS(running_time_diff),
1123 GST_TIME_ARGS(timestamp - running_time_diff));
1126 timestamp -= running_time_diff;
1128 /* That case is invalid for QoS events */
1129 if (diff < 0 && -diff > timestamp) {
1130 LOGW("QOS event from previous group");
1131 ret = GST_PAD_PROBE_DROP;
1135 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1136 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1146 gst_caps_unref(caps);
1150 /* create fakesink for audio or video path without audiobin or videobin */
1152 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1154 GstElement *pipeline = NULL;
1155 GstElement *fakesink = NULL;
1156 GstPad *sinkpad = NULL;
1159 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1164 fakesink = gst_element_factory_make("fakesink", NULL);
1165 if (fakesink == NULL) {
1166 LOGE("failed to create fakesink");
1170 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1171 LOGE("failed to add fakesink to pipeline");
1176 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1178 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1180 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1181 LOGE("failed to link fakesink");
1185 if (strstr(name, "video")) {
1186 if (player->v_stream_caps) {
1187 gst_caps_unref(player->v_stream_caps);
1188 player->v_stream_caps = NULL;
1190 if (player->ini.set_dump_element_flag)
1191 __mmplayer_add_dump_buffer_probe(player, fakesink);
1194 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1195 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1197 /* store it as it's sink element */
1198 __mmplayer_add_sink(player, fakesink, FALSE);
1201 gst_object_unref(GST_OBJECT(sinkpad));
1209 gst_object_unref(GST_OBJECT(sinkpad));
1212 gst_element_set_state(fakesink, GST_STATE_NULL);
1214 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1215 gst_object_unref(GST_OBJECT(fakesink));
1222 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1224 GstElement *pipeline = NULL;
1225 g_autoptr(GstElement) concat = NULL;
1226 g_autoptr(GstPad) srcpad = NULL;
1229 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1231 concat = gst_element_factory_make("concat", NULL);
1233 LOGE("failed to create concat");
1237 srcpad = gst_element_get_static_pad(concat, "src");
1239 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1240 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1241 __mmplayer_gst_combiner_blocked, NULL, NULL);
1242 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1243 __mmplayer_gst_combiner_event_probe, player, NULL);
1246 gst_element_set_state(concat, GST_STATE_PAUSED);
1248 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1249 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1250 LOGE("failed to add concat to pipeline");
1251 gst_element_set_state(concat, GST_STATE_NULL);
1255 LOGD("Create concat [%d] element", elem_idx);
1257 player->pipeline->mainbin[elem_idx].id = elem_idx;
1258 player->pipeline->mainbin[elem_idx].gst = concat;
1261 return g_steal_pointer(&concat);
1265 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1267 GstElement *pipeline = NULL;
1268 GstElement *selector = NULL;
1269 GstPad *srcpad = NULL;
1272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1274 selector = gst_element_factory_make("input-selector", NULL);
1276 LOGE("failed to create input-selector");
1279 g_object_set(selector, "sync-streams", TRUE, NULL);
1281 srcpad = gst_element_get_static_pad(selector, "src");
1283 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1284 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1285 __mmplayer_gst_combiner_blocked, NULL, NULL);
1286 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1287 __mmplayer_gst_combiner_event_probe, player, NULL);
1289 gst_element_set_state(selector, GST_STATE_PAUSED);
1291 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1292 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1293 LOGE("failed to add selector to pipeline");
1295 if (player->track[stream_type].block_id != 0)
1296 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1297 player->track[stream_type].block_id = 0;
1299 if (player->track[stream_type].event_probe_id != 0)
1300 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1301 player->track[stream_type].event_probe_id = 0;
1303 gst_object_unref(GST_OBJECT(srcpad));
1305 gst_element_set_state(selector, GST_STATE_NULL);
1306 gst_object_unref(GST_OBJECT(selector));
1310 gst_object_unref(GST_OBJECT(srcpad));
1312 player->pipeline->mainbin[elem_idx].id = elem_idx;
1313 player->pipeline->mainbin[elem_idx].gst = selector;
1320 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1322 mmplayer_t *player = (mmplayer_t *)data;
1323 GstElement *combiner = NULL;
1324 GstCaps *caps = NULL;
1325 GstStructure *str = NULL;
1326 const gchar *name = NULL;
1327 GstPad *sinkpad = NULL;
1328 gboolean first_track = FALSE;
1329 gboolean caps_ret = TRUE;
1331 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1332 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1335 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1336 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1338 LOGD("pad-added signal handling");
1340 /* get mimetype from caps */
1341 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1345 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1347 LOGD("detected mimetype : %s", name);
1350 if (strstr(name, "video")) {
1352 gchar *caps_str = NULL;
1354 caps_str = gst_caps_to_string(caps);
1355 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1356 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1357 player->set_mode.video_zc = true;
1359 MMPLAYER_FREEIF(caps_str);
1361 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1362 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1364 LOGD("surface type : %d", stype);
1366 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1367 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1371 /* in case of exporting video frame, it requires the 360 video filter.
1372 * it will be handled in _no_more_pads(). */
1373 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1374 __mmplayer_gst_make_fakesink(player, pad, name);
1378 if (MMPLAYER_USE_DECODEBIN(player)) {
1379 LOGD("video selector is required");
1380 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1382 LOGD("video concat is required");
1383 elem_idx = MMPLAYER_M_V_CONCAT;
1385 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1386 } else if (strstr(name, "audio")) {
1387 gint samplerate = 0;
1390 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1391 if (player->build_audio_offload)
1392 player->no_more_pad = TRUE; /* remove state holder */
1393 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1397 gst_structure_get_int(str, "rate", &samplerate);
1398 gst_structure_get_int(str, "channels", &channels);
1400 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1401 __mmplayer_gst_make_fakesink(player, pad, name);
1404 if (MMPLAYER_USE_DECODEBIN(player)) {
1405 LOGD("audio selector is required");
1406 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1408 LOGD("audio concat is required");
1409 elem_idx = MMPLAYER_M_A_CONCAT;
1411 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1413 } else if (strstr(name, "text")) {
1414 if (MMPLAYER_USE_DECODEBIN(player)) {
1415 LOGD("text selector is required");
1416 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1418 LOGD("text concat is required");
1419 elem_idx = MMPLAYER_M_T_CONCAT;
1421 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1423 LOGE("invalid caps info");
1427 /* check selector and create it */
1428 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1429 if (MMPLAYER_USE_DECODEBIN(player))
1430 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1432 combiner = __mmplayer_gst_make_concat(player, elem_idx, stream_type);
1438 LOGD("Combiner element is already created.");
1442 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1444 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1446 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1447 LOGE("failed to link combiner");
1448 gst_object_unref(GST_OBJECT(combiner));
1453 if (MMPLAYER_USE_DECODEBIN(player)) {
1454 LOGD("this track will be activated");
1455 g_object_set(combiner, "active-pad", sinkpad, NULL);
1459 if (MMPLAYER_USE_DECODEBIN(player)) {
1460 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1462 /* apply the text track information */
1463 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1464 mm_player_set_attribute((MMHandleType)player, NULL,
1465 "content_text_track_num", player->track[stream_type].total_track_num,
1466 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1467 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1474 gst_caps_unref(caps);
1477 gst_object_unref(GST_OBJECT(sinkpad));
1481 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1486 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1488 GstPad *srcpad = NULL;
1491 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1493 LOGD("type %d", type);
1496 LOGD("there is no %d track", type);
1500 srcpad = gst_element_get_static_pad(combiner, "src");
1502 LOGE("failed to get srcpad from combiner");
1506 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1508 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1510 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1511 if (player->track[type].block_id) {
1512 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1513 player->track[type].block_id = 0;
1517 gst_object_unref(GST_OBJECT(srcpad));
1526 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1528 gint active_index = 0;
1531 MMPLAYER_RETURN_IF_FAIL(player);
1533 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1535 /* change track to active pad */
1536 active_index = player->track[type].active_track_index;
1537 if ((active_index != DEFAULT_TRACK_INDEX) &&
1538 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1539 LOGW("failed to change %d type track to %d", type, active_index);
1540 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1544 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1545 mm_player_set_attribute((MMHandleType)player, NULL,
1546 "content_text_track_num", player->track[type].total_track_num,
1547 "current_text_track_index", player->track[type].active_track_index, NULL);
1554 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1557 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1559 if (!audio_selector) {
1560 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1562 /* in case the source is changed, output can be changed. */
1563 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1564 LOGD("remove previous audiobin if it exist");
1566 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1567 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1569 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1570 MMPLAYER_FREEIF(player->pipeline->audiobin);
1573 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1574 _mmplayer_pipeline_complete(NULL, player);
1579 /* apply the audio track information */
1580 if (MMPLAYER_USE_DECODEBIN(player))
1581 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1583 /* create audio sink path */
1584 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1585 LOGE("failed to create audio sink path");
1594 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1597 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1599 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1600 LOGD("text path is not supported");
1604 /* apply the text track information */
1605 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1607 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1608 player->has_closed_caption = TRUE;
1610 /* create text decode path */
1611 player->no_more_pad = TRUE;
1613 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1614 LOGE("failed to create text sink path");
1623 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1625 gint64 dur_bytes = 0L;
1628 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1629 player->pipeline->mainbin && player->streamer, FALSE);
1631 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1632 LOGE("fail to get duration.");
1634 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1635 * use file information was already set on Q2 when it was created. */
1636 _mm_player_streaming_set_queue2(player->streamer,
1637 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1638 TRUE, /* use_buffering */
1639 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1640 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1647 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1649 mmplayer_t *player = NULL;
1650 GstElement *video_selector = NULL;
1651 GstElement *audio_selector = NULL;
1652 GstElement *text_selector = NULL;
1655 player = (mmplayer_t *)data;
1657 LOGD("no-more-pad signal handling");
1659 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1660 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1661 LOGW("player is shutting down");
1665 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1666 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1667 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1668 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1669 LOGE("failed to set queue2 buffering");
1674 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1675 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1676 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1678 if (!video_selector && !audio_selector && !text_selector) {
1679 LOGW("there is no selector");
1680 player->no_more_pad = TRUE;
1684 /* create video path followed by video-select */
1685 if (video_selector && !audio_selector && !text_selector)
1686 player->no_more_pad = TRUE;
1688 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1691 /* create audio path followed by audio-select */
1692 if (audio_selector && !text_selector)
1693 player->no_more_pad = TRUE;
1695 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1698 /* create text path followed by text-select */
1699 __mmplayer_create_text_sink_path(player, text_selector);
1702 _mmplayer_set_reconfigure_state(player, FALSE);
1707 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1709 gboolean ret = FALSE;
1710 GstElement *pipeline = NULL;
1711 GstPad *sinkpad = NULL;
1714 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1717 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1719 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1721 LOGE("failed to get pad from sinkbin");
1727 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1728 LOGE("failed to link sinkbin for reusing");
1729 goto EXIT; /* exit either pass or fail */
1733 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1734 LOGE("failed to set state(READY) to sinkbin");
1739 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1740 LOGE("failed to add sinkbin to pipeline");
1745 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1746 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1751 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1752 LOGE("failed to set state(PAUSED) to sinkbin");
1761 gst_object_unref(GST_OBJECT(sinkpad));
1769 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1771 mmplayer_t *player = NULL;
1772 GstCaps *caps = NULL;
1773 gchar *caps_str = NULL;
1774 GstStructure *str = NULL;
1775 const gchar *name = NULL;
1776 GstElement *sinkbin = NULL;
1777 gboolean reusing = FALSE;
1778 gboolean caps_ret = TRUE;
1779 gchar *sink_pad_name = "sink";
1782 player = (mmplayer_t *)data;
1785 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1786 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1787 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1789 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1793 gst_caps_unref(caps);
1794 caps = gst_caps_ref(ref_caps);
1797 caps_str = gst_caps_to_string(caps);
1799 LOGD("detected mimetype : %s", name);
1801 if (strstr(name, "audio")) {
1802 if (player->pipeline->audiobin == NULL) {
1803 const gchar *audio_format = gst_structure_get_string(str, "format");
1805 LOGD("original audio format %s", audio_format);
1806 mm_player_set_attribute((MMHandleType)player, NULL,
1807 "content_audio_format", audio_format, strlen(audio_format), NULL);
1810 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1811 LOGE("failed to create audiobin. continuing without audio");
1815 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1816 LOGD("creating audiobin success");
1819 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1820 LOGD("reusing audiobin");
1821 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1823 } else if (strstr(name, "video")) {
1824 /* 1. zero copy is updated at _decode_pad_added()
1825 * 2. NULL surface type is handled in _decode_pad_added() */
1826 LOGD("zero copy %d", player->set_mode.video_zc);
1827 if (player->pipeline->videobin == NULL) {
1828 int surface_type = 0;
1829 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1830 LOGD("display_surface_type (%d)", surface_type);
1832 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1833 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1834 LOGE("failed to acquire video overlay resource");
1838 player->interrupted_by_resource = FALSE;
1840 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1841 LOGE("failed to create videobin. continuing without video");
1845 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1846 LOGD("creating videosink bin success");
1849 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1850 LOGD("re-using videobin");
1851 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1853 } else if (strstr(name, "text")) {
1854 if (player->pipeline->textbin == NULL) {
1855 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1856 LOGE("failed to create text sink bin. continuing without text");
1860 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1861 player->textsink_linked = 1;
1862 LOGD("creating textsink bin success");
1864 if (!player->textsink_linked) {
1865 LOGD("re-using textbin");
1867 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1868 player->textsink_linked = 1;
1870 /* linked textbin exist which means that the external subtitle path exist already */
1871 LOGW("ignoring internal subtitle since external subtitle is available");
1874 sink_pad_name = "text_sink";
1876 LOGW("unknown mime type %s, ignoring it", name);
1880 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1883 LOGD("[handle: %p] success to create and link sink bin", player);
1885 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1886 * streaming task. if the task blocked, then buffer will not flow to the next element
1887 *(autoplugging element). so this is special hack for streaming. please try to remove it
1889 /* dec stream count. we can remove fakesink if it's zero */
1890 if (player->num_dynamic_pad)
1891 player->num_dynamic_pad--;
1893 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1895 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1896 _mmplayer_pipeline_complete(NULL, player);
1900 MMPLAYER_FREEIF(caps_str);
1903 gst_caps_unref(caps);
1909 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1911 int required_angle = 0; /* Angle required for straight view */
1912 int rotation_angle = 0;
1914 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1915 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1917 /* Counter clockwise */
1918 switch (orientation) {
1923 required_angle = 270;
1926 required_angle = 180;
1929 required_angle = 90;
1933 rotation_angle = display_angle + required_angle;
1934 if (rotation_angle >= 360)
1935 rotation_angle -= 360;
1937 /* check if supported or not */
1938 if (rotation_angle % 90) {
1939 LOGD("not supported rotation angle = %d", rotation_angle);
1943 switch (rotation_angle) {
1945 *value = MM_DISPLAY_ROTATION_NONE;
1948 *value = MM_DISPLAY_ROTATION_90;
1951 *value = MM_DISPLAY_ROTATION_180;
1954 *value = MM_DISPLAY_ROTATION_270;
1958 LOGD("setting rotation property value : %d", *value);
1964 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1966 int display_rotation = 0;
1967 gchar *org_orient = NULL;
1968 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1971 LOGE("cannot get content attribute");
1972 return MM_ERROR_PLAYER_INTERNAL;
1975 if (display_angle) {
1976 /* update user rotation */
1977 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1979 /* Counter clockwise */
1980 switch (display_rotation) {
1981 case MM_DISPLAY_ROTATION_NONE:
1984 case MM_DISPLAY_ROTATION_90:
1985 *display_angle = 90;
1987 case MM_DISPLAY_ROTATION_180:
1988 *display_angle = 180;
1990 case MM_DISPLAY_ROTATION_270:
1991 *display_angle = 270;
1994 LOGW("wrong angle type : %d", display_rotation);
1997 LOGD("check user angle: %d", *display_angle);
2001 /* Counter clockwise */
2002 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2005 if (!strcmp(org_orient, "rotate-90"))
2007 else if (!strcmp(org_orient, "rotate-180"))
2009 else if (!strcmp(org_orient, "rotate-270"))
2012 LOGD("original rotation is %s", org_orient);
2014 LOGD("content_video_orientation get fail");
2017 LOGD("check orientation: %d", *orientation);
2020 return MM_ERROR_NONE;
2023 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2025 int rotation_value = 0;
2026 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2027 int display_angle = 0;
2030 /* check video sinkbin is created */
2031 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2034 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2036 /* get rotation value to set */
2037 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2039 LOGD("set video param : rotate %d", rotation_value);
2042 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2044 MMHandleType attrs = 0;
2048 /* check video sinkbin is created */
2049 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2050 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2053 attrs = MMPLAYER_GET_ATTRS(player);
2054 MMPLAYER_RETURN_IF_FAIL(attrs);
2056 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2057 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2058 LOGD("set video param : visible %d", visible);
2061 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2063 MMHandleType attrs = 0;
2064 int display_method = 0;
2067 /* check video sinkbin is created */
2068 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2071 attrs = MMPLAYER_GET_ATTRS(player);
2072 MMPLAYER_RETURN_IF_FAIL(attrs);
2074 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2075 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2076 LOGD("set video param : method %d", display_method);
2079 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2081 MMHandleType attrs = 0;
2085 /* check video sinkbin is created */
2086 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2089 attrs = MMPLAYER_GET_ATTRS(player);
2090 MMPLAYER_RETURN_IF_FAIL(attrs);
2092 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2093 MMPLAYER_RETURN_IF_FAIL(handle);
2095 gst_video_overlay_set_video_roi_area(
2096 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2097 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2098 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2099 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2102 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2104 MMHandleType attrs = 0;
2109 int win_roi_width = 0;
2110 int win_roi_height = 0;
2113 /* check video sinkbin is created */
2114 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2117 attrs = MMPLAYER_GET_ATTRS(player);
2118 MMPLAYER_RETURN_IF_FAIL(attrs);
2120 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2121 MMPLAYER_RETURN_IF_FAIL(handle);
2123 /* It should be set after setting window */
2124 mm_attrs_multiple_get(attrs, NULL,
2125 "display_win_roi_x", &win_roi_x,
2126 "display_win_roi_y", &win_roi_y,
2127 "display_win_roi_width", &win_roi_width,
2128 "display_win_roi_height", &win_roi_height, NULL);
2130 /* After setting window handle, set display roi area */
2131 gst_video_overlay_set_display_roi_area(
2132 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2133 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2134 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2135 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2138 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2140 MMHandleType attrs = 0;
2141 gchar *handle = NULL;
2143 /* check video sinkbin is created */
2144 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2147 attrs = MMPLAYER_GET_ATTRS(player);
2148 MMPLAYER_RETURN_IF_FAIL(attrs);
2150 /* common case if using overlay surface */
2151 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2152 MMPLAYER_RETURN_IF_FAIL(handle);
2154 gst_video_overlay_set_wl_window_exported_shell_handle(
2155 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2157 LOGD("set video param: exported_shell_handle (%s)", handle);
2160 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2162 MMHandleType attrs = 0;
2165 /* check video sinkbin is created */
2166 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2169 attrs = MMPLAYER_GET_ATTRS(player);
2170 MMPLAYER_RETURN_IF_FAIL(attrs);
2172 /* common case if using overlay surface */
2173 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2174 MMPLAYER_RETURN_IF_FAIL(handle);
2176 /* default is using wl_surface_id */
2177 LOGD("set video param : wl_surface_id %d", handle);
2178 gst_video_overlay_set_wl_window_wl_surface_id(
2179 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2184 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2186 gboolean update_all_param = FALSE;
2187 int curr_type = MM_DISPLAY_SURFACE_NUM;
2191 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2192 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2193 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2194 LOGW("videosink is not ready yet");
2195 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2198 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2200 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2201 LOGE("current type(%d) is wrong", curr_type);
2202 return MM_ERROR_PLAYER_INTERNAL;
2205 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2206 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2207 return MM_ERROR_PLAYER_INTERNAL;
2210 LOGD("param_name : %s", param_name);
2211 if (!g_strcmp0(param_name, "update_all_param"))
2212 update_all_param = TRUE;
2214 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2215 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2217 return MM_ERROR_NONE;
2219 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2220 __mmplayer_video_param_set_display_overlay(player);
2221 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2222 __mmplayer_video_param_set_display_method(player);
2223 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2224 __mmplayer_video_param_set_display_visible(player);
2225 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2226 __mmplayer_video_param_set_display_rotation(player);
2227 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2228 __mmplayer_video_param_set_roi_area(player);
2229 if (update_all_param)
2230 __mmplayer_video_param_set_video_roi_area(player);
2233 return MM_ERROR_NONE;
2236 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2238 gboolean disable_overlay = FALSE;
2241 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2242 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2243 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2245 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2246 LOGW("Display control is not supported");
2247 return MM_ERROR_PLAYER_INTERNAL;
2250 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2252 if (disable == (bool)disable_overlay) {
2253 LOGE("It's the same with current setting: (%d)", disable);
2254 return MM_ERROR_NONE;
2258 LOGE("disable overlay");
2259 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2261 /* release overlay resource */
2262 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2263 LOGE("failed to release overlay resource");
2264 return MM_ERROR_PLAYER_INTERNAL;
2267 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2268 LOGE("failed to acquire video overlay resource");
2269 return MM_ERROR_PLAYER_INTERNAL;
2271 player->interrupted_by_resource = FALSE;
2273 LOGD("enable overlay");
2274 __mmplayer_video_param_set_display_overlay(player);
2275 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2276 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2280 return MM_ERROR_NONE;
2284 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2286 int ret = MM_ERROR_NONE;
2287 mmplayer_t *player = (mmplayer_t *)hplayer;
2290 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2292 if (MMPLAYER_USE_DECODEBIN(player)) {
2293 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2298 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2299 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2300 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2302 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2304 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2306 /* release decoder resource */
2307 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2308 LOGE("failed to release video decoder resources");
2309 return MM_ERROR_PLAYER_INTERNAL;
2311 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2313 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2317 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2324 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2326 GList *bucket = element_bucket;
2327 mmplayer_gst_element_t *element = NULL;
2328 mmplayer_gst_element_t *prv_element = NULL;
2329 GstElement *tee_element = NULL;
2330 gint successful_link_count = 0;
2334 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2336 prv_element = (mmplayer_gst_element_t *)bucket->data;
2337 bucket = bucket->next;
2339 for (; bucket; bucket = bucket->next) {
2340 element = (mmplayer_gst_element_t *)bucket->data;
2342 if (element && element->gst) {
2343 if (prv_element && prv_element->gst) {
2344 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2346 prv_element->gst = tee_element;
2348 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2349 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2350 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2354 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2355 LOGD("linking [%s] to [%s] success",
2356 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2357 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2358 successful_link_count++;
2359 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2360 LOGD("keep audio-tee element for next audio pipeline branch");
2361 tee_element = prv_element->gst;
2364 LOGD("linking [%s] to [%s] failed",
2365 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2366 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2372 prv_element = element;
2377 return successful_link_count;
2381 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2383 GList *bucket = element_bucket;
2384 mmplayer_gst_element_t *element = NULL;
2385 int successful_add_count = 0;
2389 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2390 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2392 for (; bucket; bucket = bucket->next) {
2393 element = (mmplayer_gst_element_t *)bucket->data;
2395 if (element && element->gst) {
2396 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2397 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2398 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2399 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2402 successful_add_count++;
2408 return successful_add_count;
2412 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2414 mmplayer_t *player = (mmplayer_t *)data;
2415 GstCaps *caps = NULL;
2416 GstStructure *str = NULL;
2418 gboolean caps_ret = TRUE;
2422 MMPLAYER_RETURN_IF_FAIL(pad);
2423 MMPLAYER_RETURN_IF_FAIL(unused);
2424 MMPLAYER_RETURN_IF_FAIL(data);
2426 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2430 LOGD("name = %s", name);
2432 if (strstr(name, "audio")) {
2433 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2435 if (player->audio_stream_changed_cb) {
2436 LOGE("call the audio stream changed cb");
2437 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2439 } else if (strstr(name, "video")) {
2440 if ((name = gst_structure_get_string(str, "format")))
2441 player->set_mode.video_zc = name[0] == 'S';
2443 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2444 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2446 LOGW("invalid caps info");
2451 gst_caps_unref(caps);
2459 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2464 MMPLAYER_RETURN_IF_FAIL(player);
2466 if (player->audio_stream_buff_list) {
2467 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2468 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2471 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2472 __mmplayer_audio_stream_send_data(player, tmp);
2474 MMPLAYER_FREEIF(tmp->pcm_data);
2475 MMPLAYER_FREEIF(tmp);
2478 g_list_free(player->audio_stream_buff_list);
2479 player->audio_stream_buff_list = NULL;
2486 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2488 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2491 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2493 audio_stream.bitrate = a_buffer->bitrate;
2494 audio_stream.channel = a_buffer->channel;
2495 audio_stream.channel_mask = a_buffer->channel_mask;
2496 audio_stream.data_size = a_buffer->data_size;
2497 audio_stream.data = a_buffer->pcm_data;
2498 audio_stream.pcm_format = a_buffer->pcm_format;
2500 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2502 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2508 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2510 mmplayer_t *player = (mmplayer_t *)data;
2511 const gchar *pcm_format = NULL;
2514 guint64 channel_mask = 0;
2515 void *a_data = NULL;
2517 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2518 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2522 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2524 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2525 a_data = mapinfo.data;
2526 a_size = mapinfo.size;
2528 GstCaps *caps = gst_pad_get_current_caps(pad);
2529 GstStructure *structure = gst_caps_get_structure(caps, 0);
2531 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2533 pcm_format = gst_structure_get_string(structure, "format");
2534 gst_structure_get_int(structure, "rate", &rate);
2535 gst_structure_get_int(structure, "channels", &channel);
2536 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2537 gst_caps_unref(GST_CAPS(caps));
2539 /* In case of the sync is false, use buffer list. *
2540 * The num of buffer list depends on the num of audio channels */
2541 if (player->audio_stream_buff_list) {
2542 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2543 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2545 if (channel_mask == tmp->channel_mask) {
2547 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2549 if (tmp->data_size + a_size < tmp->buff_size) {
2550 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2551 tmp->data_size += a_size;
2553 /* send data to client */
2554 __mmplayer_audio_stream_send_data(player, tmp);
2556 if (a_size > tmp->buff_size) {
2557 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2558 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2559 if (tmp->pcm_data == NULL) {
2560 LOGE("failed to realloc data.");
2563 tmp->buff_size = a_size;
2565 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2566 memcpy(tmp->pcm_data, a_data, a_size);
2567 tmp->data_size = a_size;
2572 LOGE("data is empty in list.");
2578 /* create new audio stream data for newly found audio channel */
2579 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2580 if (a_buffer == NULL) {
2581 LOGE("failed to alloc data.");
2584 a_buffer->bitrate = rate;
2585 a_buffer->channel = channel;
2586 a_buffer->channel_mask = channel_mask;
2587 a_buffer->data_size = a_size;
2588 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2590 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2591 /* If sync is FALSE, use buffer list to reduce the IPC. */
2592 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2593 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2594 if (a_buffer->pcm_data == NULL) {
2595 LOGE("failed to alloc data.");
2596 MMPLAYER_FREEIF(a_buffer);
2599 memcpy(a_buffer->pcm_data, a_data, a_size);
2601 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2603 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2605 /* If sync is TRUE, send data directly. */
2606 a_buffer->pcm_data = a_data;
2607 __mmplayer_audio_stream_send_data(player, a_buffer);
2608 MMPLAYER_FREEIF(a_buffer);
2612 gst_buffer_unmap(buffer, &mapinfo);
2617 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2619 mmplayer_t *player = (mmplayer_t *)data;
2620 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2621 GstPad *sinkpad = NULL;
2622 GstElement *queue = NULL, *sink = NULL;
2625 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2627 queue = gst_element_factory_make("queue", NULL);
2628 if (queue == NULL) {
2629 LOGD("fail make queue");
2633 sink = gst_element_factory_make("fakesink", NULL);
2635 LOGD("fail make fakesink");
2639 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2641 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2642 LOGW("failed to link queue & sink");
2646 sinkpad = gst_element_get_static_pad(queue, "sink");
2648 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2649 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2653 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2655 gst_object_unref(sinkpad);
2656 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2657 g_object_set(sink, "sync", TRUE, NULL);
2658 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2660 /* keep the first sink reference only */
2661 if (!audiobin[MMPLAYER_A_SINK].gst) {
2662 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2663 audiobin[MMPLAYER_A_SINK].gst = sink;
2667 _mmplayer_add_signal_connection(player,
2669 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2671 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2674 __mmplayer_add_sink(player, sink, FALSE);
2676 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2677 LOGE("failed to sync state");
2681 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2682 LOGE("failed to sync state");
2690 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2692 gst_object_unref(GST_OBJECT(queue));
2696 gst_object_unref(GST_OBJECT(sink));
2700 gst_object_unref(GST_OBJECT(sinkpad));
2708 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2710 mmplayer_t *player = (mmplayer_t *)data;
2713 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2715 player->no_more_pad = TRUE;
2716 _mmplayer_pipeline_complete(NULL, player);
2723 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2725 #define MAX_PROPS_LEN 128
2726 mmplayer_gst_element_t *audiobin = NULL;
2727 gint latency_mode = 0;
2728 gchar *stream_type = NULL;
2729 gchar *latency = NULL;
2731 gchar stream_props[MAX_PROPS_LEN] = {0,};
2732 GstStructure *props = NULL;
2735 * It should be set after player creation through attribute.
2736 * But, it can not be changed during playing.
2739 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2741 audiobin = player->pipeline->audiobin;
2743 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2744 if (player->sound.mute) {
2745 LOGD("mute enabled");
2746 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2749 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2750 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2753 snprintf(stream_props, sizeof(stream_props) - 1,
2754 "props,application.process.id.origin=%d", player->client_pid);
2756 snprintf(stream_props, sizeof(stream_props) - 1,
2757 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2758 stream_type, stream_id, player->client_pid);
2760 props = gst_structure_from_string(stream_props, NULL);
2761 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2762 LOGI("props result[%s].", stream_props);
2763 gst_structure_free(props);
2765 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2767 switch (latency_mode) {
2768 case AUDIO_LATENCY_MODE_LOW:
2769 latency = g_strdup("low");
2771 case AUDIO_LATENCY_MODE_MID:
2772 latency = g_strdup("mid");
2774 case AUDIO_LATENCY_MODE_HIGH:
2775 latency = g_strdup("high");
2778 latency = g_strdup("mid");
2782 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2784 LOGD("audiosink property - latency=%s", latency);
2786 MMPLAYER_FREEIF(latency);
2792 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2794 mmplayer_gst_element_t *audiobin = NULL;
2797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2798 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2800 audiobin = player->pipeline->audiobin;
2802 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2803 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2804 LOGE("failed to create media stream info");
2805 return MM_ERROR_PLAYER_INTERNAL;
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2810 if (player->video360_yaw_radians <= M_PI &&
2811 player->video360_yaw_radians >= -M_PI &&
2812 player->video360_pitch_radians <= M_PI_2 &&
2813 player->video360_pitch_radians >= -M_PI_2) {
2814 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2815 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2816 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2817 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2818 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2819 "source-orientation-y", player->video360_metadata.init_view_heading,
2820 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2824 return MM_ERROR_NONE;
2828 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2830 mmplayer_gst_element_t *audiobin = NULL;
2831 GstPad *sink_pad = NULL;
2832 GstCaps *acaps = NULL;
2834 int pitch_control = 0;
2835 double pitch_value = 1.0;
2838 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2839 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2841 audiobin = player->pipeline->audiobin;
2843 LOGD("make element for normal audio playback");
2845 /* audio bin structure for playback. {} means optional.
2846 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2848 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2849 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2852 /* for pitch control */
2853 mm_attrs_multiple_get(player->attrs, NULL,
2854 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2855 MM_PLAYER_PITCH_VALUE, &pitch_value,
2858 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2859 if (pitch_control && (player->videodec_linked == 0)) {
2860 GstElementFactory *factory;
2862 factory = gst_element_factory_find("pitch");
2864 gst_object_unref(factory);
2867 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2870 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2871 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2873 LOGW("there is no pitch element");
2878 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2880 /* replaygain volume */
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2882 if (player->sound.rg_enable)
2883 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2885 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2890 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2891 /* currently, only openalsink uses volume element */
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2893 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2895 if (player->sound.mute) {
2896 LOGD("mute enabled");
2897 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2901 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2903 /* audio effect element. if audio effect is enabled */
2904 if ((strcmp(player->ini.audioeffect_element, ""))
2906 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2907 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2909 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2911 if ((!player->bypass_audio_effect)
2912 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2913 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2914 if (!_mmplayer_audio_effect_custom_apply(player))
2915 LOGI("apply audio effect(custom) setting success");
2919 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2920 && (player->set_mode.rich_audio)) {
2921 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2925 /* create audio sink */
2926 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2927 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2928 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2930 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2931 if (player->is_360_feature_enabled &&
2932 player->is_content_spherical &&
2934 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2935 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2936 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2938 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2940 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2942 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2943 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2944 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2945 gst_caps_unref(acaps);
2947 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2949 player->is_openal_plugin_used = TRUE;
2951 if (player->is_360_feature_enabled && player->is_content_spherical)
2952 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2953 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2956 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2957 (player->videodec_linked && player->ini.use_system_clock)) {
2958 LOGD("system clock will be used.");
2959 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2962 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2963 __mmplayer_gst_set_pulsesink_property(player);
2964 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2965 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2970 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2971 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2973 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2974 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2975 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2976 gst_object_unref(GST_OBJECT(sink_pad));
2978 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2981 return MM_ERROR_NONE;
2983 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2985 return MM_ERROR_PLAYER_INTERNAL;
2989 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2991 mmplayer_gst_element_t *audiobin = NULL;
2992 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2994 gchar *dst_format = NULL;
2996 int dst_samplerate = 0;
2997 int dst_channels = 0;
2998 GstCaps *caps = NULL;
2999 char *caps_str = NULL;
3002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3003 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3005 audiobin = player->pipeline->audiobin;
3007 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
3009 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
3011 [case 1] extract interleave audio pcm without playback
3012 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
3013 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
3015 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
3017 [case 2] deinterleave for each channel without playback
3018 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
3019 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
3021 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
3022 - fakesink (sync or not)
3025 [case 3] [case 1(sync only)] + playback
3026 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3028 * src - ... - tee - queue1 - playback path
3029 - queue2 - [case1 pipeline with sync]
3031 [case 4] [case 2(sync only)] + playback
3032 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3034 * src - ... - tee - queue1 - playback path
3035 - queue2 - [case2 pipeline with sync]
3039 /* 1. create tee and playback path
3040 'tee' should be added at first to copy the decoded stream
3042 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3043 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3044 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3046 /* tee - path 1 : for playback path */
3047 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3048 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3050 /* tee - path 2 : for extract path */
3051 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3052 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3055 /* if there is tee, 'tee - path 2' is linked here */
3057 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3060 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3062 /* 2. decide the extract pcm format */
3063 mm_attrs_multiple_get(player->attrs, NULL,
3064 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3065 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3066 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3069 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3070 dst_format, dst_len, dst_samplerate, dst_channels);
3072 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3073 mm_attrs_multiple_get(player->attrs, NULL,
3074 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3075 "content_audio_samplerate", &dst_samplerate,
3076 "content_audio_channels", &dst_channels,
3079 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3080 dst_format, dst_len, dst_samplerate, dst_channels);
3082 /* If there is no enough information, set it to platform default value. */
3083 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3084 LOGD("set platform default format");
3085 dst_format = DEFAULT_PCM_OUT_FORMAT;
3087 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3088 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3091 /* 3. create capsfilter */
3092 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3093 caps = gst_caps_new_simple("audio/x-raw",
3094 "format", G_TYPE_STRING, dst_format,
3095 "rate", G_TYPE_INT, dst_samplerate,
3096 "channels", G_TYPE_INT, dst_channels,
3099 caps_str = gst_caps_to_string(caps);
3100 LOGD("new caps : %s", caps_str);
3102 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3105 gst_caps_unref(caps);
3106 MMPLAYER_FREEIF(caps_str);
3108 /* 4-1. create deinterleave to extract pcm for each channel */
3109 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3110 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3111 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3113 /* audiosink will be added after getting signal for each channel */
3114 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3115 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3116 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3117 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3118 player->no_more_pad = FALSE;
3120 /* 4-2. create fakesink to extract interleaved pcm */
3121 LOGD("add audio fakesink for interleaved audio");
3122 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3123 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3124 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3125 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3127 _mmplayer_add_signal_connection(player,
3128 G_OBJECT(audiobin[extract_sink_id].gst),
3129 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3131 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3134 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3138 return MM_ERROR_NONE;
3140 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3142 return MM_ERROR_PLAYER_INTERNAL;
3146 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3148 int ret = MM_ERROR_NONE;
3149 mmplayer_gst_element_t *audiobin = NULL;
3150 GList *element_bucket = NULL;
3153 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3154 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3156 audiobin = player->pipeline->audiobin;
3158 if (player->build_audio_offload) { /* skip all the audio filters */
3159 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3161 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3162 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3163 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3165 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3169 /* FIXME: need to mention the supportable condition at API reference */
3170 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3171 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3173 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3175 if (ret != MM_ERROR_NONE)
3178 LOGD("success to make audio bin element");
3179 *bucket = element_bucket;
3182 return MM_ERROR_NONE;
3185 LOGE("failed to make audio bin element");
3186 g_list_free(element_bucket);
3190 return MM_ERROR_PLAYER_INTERNAL;
3194 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3196 mmplayer_gst_element_t *first_element = NULL;
3197 mmplayer_gst_element_t *audiobin = NULL;
3199 GstPad *ghostpad = NULL;
3200 GList *element_bucket = NULL;
3204 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3207 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3209 LOGE("failed to allocate memory for audiobin");
3210 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3214 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3215 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3216 if (!audiobin[MMPLAYER_A_BIN].gst) {
3217 LOGE("failed to create audiobin");
3222 player->pipeline->audiobin = audiobin;
3224 /* create audio filters and audiosink */
3225 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3228 /* adding created elements to bin */
3229 LOGD("adding created elements to bin");
3230 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3233 /* linking elements in the bucket by added order. */
3234 LOGD("Linking elements in the bucket by added order.");
3235 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3238 /* get first element's sinkpad for creating ghostpad */
3239 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3240 if (!first_element) {
3241 LOGE("failed to get first elem");
3245 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3247 LOGE("failed to get pad from first element of audiobin");
3251 ghostpad = gst_ghost_pad_new("sink", pad);
3253 LOGE("failed to create ghostpad");
3257 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3258 LOGE("failed to add ghostpad to audiobin");
3262 gst_object_unref(pad);
3264 g_list_free(element_bucket);
3267 return MM_ERROR_NONE;
3270 LOGD("ERROR : releasing audiobin");
3273 gst_object_unref(GST_OBJECT(pad));
3276 gst_object_unref(GST_OBJECT(ghostpad));
3279 g_list_free(element_bucket);
3281 /* release element which are not added to bin */
3282 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3283 /* NOTE : skip bin */
3284 if (audiobin[i].gst) {
3285 GstObject *parent = NULL;
3286 parent = gst_element_get_parent(audiobin[i].gst);
3289 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3290 audiobin[i].gst = NULL;
3292 gst_object_unref(GST_OBJECT(parent));
3296 /* release audiobin with it's children */
3297 if (audiobin[MMPLAYER_A_BIN].gst)
3298 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3300 MMPLAYER_FREEIF(audiobin);
3302 player->pipeline->audiobin = NULL;
3304 return MM_ERROR_PLAYER_INTERNAL;
3308 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3310 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3314 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3316 int ret = MM_ERROR_NONE;
3318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3319 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3321 MMPLAYER_VIDEO_BO_LOCK(player);
3323 if (player->video_bo_list) {
3324 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3325 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3326 if (tmp && tmp->bo == bo) {
3328 LOGD("release bo %p", bo);
3329 tbm_bo_unref(tmp->bo);
3330 MMPLAYER_VIDEO_BO_UNLOCK(player);
3331 MMPLAYER_VIDEO_BO_SIGNAL(player);
3336 /* hw codec is running or the list was reset for DRC. */
3337 LOGW("there is no bo list.");
3339 MMPLAYER_VIDEO_BO_UNLOCK(player);
3341 LOGW("failed to find bo %p", bo);
3345 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3351 tbm_bo_unref(tmp->bo);
3356 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3359 MMPLAYER_RETURN_IF_FAIL(player);
3361 MMPLAYER_VIDEO_BO_LOCK(player);
3362 if (player->video_bo_list) {
3363 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3364 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3365 player->video_bo_list = NULL;
3367 player->video_bo_size = 0;
3368 MMPLAYER_VIDEO_BO_UNLOCK(player);
3375 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3378 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3379 gboolean ret = TRUE;
3380 gint64 end_time = 0;
3382 /* check DRC, if it is, destroy the prev bo list to create again */
3383 if (player->video_bo_size != size) {
3384 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3385 __mmplayer_video_stream_destroy_bo_list(player);
3386 player->video_bo_size = size;
3389 MMPLAYER_VIDEO_BO_LOCK(player);
3391 if ((!player->video_bo_list) ||
3392 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3394 /* create bo list */
3396 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3398 if (player->video_bo_list) {
3399 /* if bo list did not created all, try it again. */
3400 idx = g_list_length(player->video_bo_list);
3401 LOGD("bo list exist(len: %d)", idx);
3404 for (; idx < player->ini.num_of_video_bo; idx++) {
3405 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3407 LOGE("Fail to alloc bo_info.");
3410 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3412 LOGE("Fail to tbm_bo_alloc.");
3413 MMPLAYER_FREEIF(bo_info);
3416 bo_info->used = FALSE;
3417 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3420 /* update video num buffers */
3421 LOGD("video_num_buffers : %d", idx);
3422 mm_player_set_attribute((MMHandleType)player, NULL,
3423 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3424 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3428 MMPLAYER_VIDEO_BO_UNLOCK(player);
3433 if (player->ini.video_bo_timeout > 0)
3434 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3437 /* get bo from list*/
3438 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3439 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3440 if (tmp && (tmp->used == FALSE)) {
3441 LOGD("found bo %p to use", tmp->bo);
3443 MMPLAYER_VIDEO_BO_UNLOCK(player);
3444 return tbm_bo_ref(tmp->bo);
3448 if (player->ini.video_bo_timeout <= 0) {
3449 MMPLAYER_VIDEO_BO_WAIT(player);
3451 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3453 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3459 MMPLAYER_VIDEO_BO_UNLOCK(player);
3464 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3466 mmplayer_t *player = (mmplayer_t *)data;
3468 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3470 /* send prerolled pkt */
3471 player->video_stream_prerolled = false;
3473 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3475 /* not to send prerolled pkt again */
3476 player->video_stream_prerolled = true;
3480 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3482 mmplayer_t *player = (mmplayer_t *)data;
3483 mmplayer_video_decoded_data_info_t *stream = NULL;
3484 GstMemory *mem = NULL;
3487 MMPLAYER_RETURN_IF_FAIL(player);
3488 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3490 if (player->video_stream_prerolled) {
3491 player->video_stream_prerolled = false;
3492 LOGD("skip the prerolled pkt not to send it again");
3496 /* clear stream data structure */
3497 stream = __mmplayer_create_stream_from_pad(pad);
3499 LOGE("failed to alloc stream");
3503 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3505 /* set size and timestamp */
3506 mem = gst_buffer_peek_memory(buffer, 0);
3507 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3508 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3510 /* check zero-copy */
3511 if (player->set_mode.video_zc &&
3512 player->set_mode.video_export &&
3513 gst_is_tizen_memory(mem)) {
3514 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3515 stream->internal_buffer = gst_buffer_ref(buffer);
3516 } else { /* sw codec */
3517 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3520 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3524 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3525 LOGE("failed to send video decoded data.");
3532 LOGE("release video stream resource.");
3533 if (gst_is_tizen_memory(mem)) {
3535 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3537 tbm_bo_unref(stream->bo[i]);
3540 /* unref gst buffer */
3541 if (stream->internal_buffer)
3542 gst_buffer_unref(stream->internal_buffer);
3545 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3547 MMPLAYER_FREEIF(stream);
3552 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3554 mmplayer_gst_element_t *videobin = NULL;
3557 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3559 videobin = player->pipeline->videobin;
3561 /* Set spatial media metadata and/or user settings to the element.
3563 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3564 "projection-type", player->video360_metadata.projection_type, NULL);
3566 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3567 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3569 if (player->video360_metadata.full_pano_width_pixels &&
3570 player->video360_metadata.full_pano_height_pixels &&
3571 player->video360_metadata.cropped_area_image_width &&
3572 player->video360_metadata.cropped_area_image_height) {
3573 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3574 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3575 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3576 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3577 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3578 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3579 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3583 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3584 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3585 "horizontal-fov", player->video360_horizontal_fov,
3586 "vertical-fov", player->video360_vertical_fov, NULL);
3589 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3590 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3591 "zoom", 1.0f / player->video360_zoom, NULL);
3594 if (player->video360_yaw_radians <= M_PI &&
3595 player->video360_yaw_radians >= -M_PI &&
3596 player->video360_pitch_radians <= M_PI_2 &&
3597 player->video360_pitch_radians >= -M_PI_2) {
3598 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3599 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3600 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3601 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3602 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3603 "pose-yaw", player->video360_metadata.init_view_heading,
3604 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3607 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3608 "passthrough", !player->is_video360_enabled, NULL);
3615 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3617 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3618 GList *element_bucket = NULL;
3621 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3623 /* create video360 filter */
3624 if (player->is_360_feature_enabled && player->is_content_spherical) {
3625 LOGD("create video360 element");
3626 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3627 __mmplayer_gst_set_video360_property(player);
3631 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3632 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3633 player->set_mode.video_zc) {
3634 LOGD("skip creating the videoconv and rotator");
3635 return MM_ERROR_NONE;
3638 /* in case of sw codec & overlay surface type, except 360 playback.
3639 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3640 LOGD("create video converter: %s", video_csc);
3641 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3644 *bucket = element_bucket;
3646 return MM_ERROR_NONE;
3648 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3649 g_list_free(element_bucket);
3653 return MM_ERROR_PLAYER_INTERNAL;
3657 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3659 gchar *factory_name = NULL;
3661 switch (surface_type) {
3662 case MM_DISPLAY_SURFACE_OVERLAY:
3664 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3665 if (strlen(player->ini.videosink_element_overlay) > 0)
3666 factory_name = player->ini.videosink_element_overlay;
3668 case MM_DISPLAY_SURFACE_REMOTE:
3670 case MM_DISPLAY_SURFACE_NULL:
3671 if (strlen(player->ini.videosink_element_fake) > 0)
3672 factory_name = player->ini.videosink_element_fake;
3675 LOGE("unidentified surface type");
3679 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3680 return factory_name;
3684 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3686 gchar *factory_name = NULL;
3687 mmplayer_gst_element_t *videobin = NULL;
3692 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3694 videobin = player->pipeline->videobin;
3695 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3697 attrs = MMPLAYER_GET_ATTRS(player);
3699 LOGE("cannot get content attribute");
3700 return MM_ERROR_PLAYER_INTERNAL;
3703 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3704 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3705 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3706 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3707 "use-tbm", use_tbm, NULL);
3710 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3711 return MM_ERROR_PLAYER_INTERNAL;
3713 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3716 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3717 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3720 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3722 LOGD("disable last-sample");
3723 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3726 if (player->set_mode.video_export) {
3728 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3729 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3730 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3732 _mmplayer_add_signal_connection(player,
3733 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3734 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3736 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3739 _mmplayer_add_signal_connection(player,
3740 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3741 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3743 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3747 if (videobin[MMPLAYER_V_SINK].gst) {
3748 GstPad *sink_pad = NULL;
3749 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3751 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3752 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3753 gst_object_unref(GST_OBJECT(sink_pad));
3755 LOGE("failed to get sink pad from videosink");
3759 return MM_ERROR_NONE;
3764 * - video overlay surface(arm/x86) : tizenwlsink
3767 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3770 GList *element_bucket = NULL;
3771 mmplayer_gst_element_t *first_element = NULL;
3772 mmplayer_gst_element_t *videobin = NULL;
3773 gchar *videosink_factory_name = NULL;
3776 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3779 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3781 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3783 player->pipeline->videobin = videobin;
3786 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3787 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3788 if (!videobin[MMPLAYER_V_BIN].gst) {
3789 LOGE("failed to create videobin");
3793 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3796 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3797 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3799 /* additional setting for sink plug-in */
3800 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3801 LOGE("failed to set video property");
3805 /* store it as it's sink element */
3806 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3808 /* adding created elements to bin */
3809 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3810 LOGE("failed to add elements");
3814 /* Linking elements in the bucket by added order */
3815 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3816 LOGE("failed to link elements");
3820 /* get first element's sinkpad for creating ghostpad */
3821 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3822 if (!first_element) {
3823 LOGE("failed to get first element from bucket");
3827 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3829 LOGE("failed to get pad from first element");
3833 /* create ghostpad */
3834 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3835 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3836 LOGE("failed to add ghostpad to videobin");
3839 gst_object_unref(pad);
3841 /* done. free allocated variables */
3842 g_list_free(element_bucket);
3846 return MM_ERROR_NONE;
3849 LOGE("ERROR : releasing videobin");
3850 g_list_free(element_bucket);
3853 gst_object_unref(GST_OBJECT(pad));
3855 /* release videobin with it's children */
3856 if (videobin[MMPLAYER_V_BIN].gst)
3857 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3859 MMPLAYER_FREEIF(videobin);
3860 player->pipeline->videobin = NULL;
3862 return MM_ERROR_PLAYER_INTERNAL;
3866 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3868 GList *element_bucket = NULL;
3869 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3871 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3872 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3873 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3874 "signal-handoffs", FALSE,
3877 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3878 _mmplayer_add_signal_connection(player,
3879 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3880 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3882 G_CALLBACK(__mmplayer_update_subtitle),
3885 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3886 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3888 if (!player->play_subtitle) {
3889 LOGD("add textbin sink as sink element of whole pipeline.");
3890 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3893 /* adding created elements to bin */
3894 LOGD("adding created elements to bin");
3895 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3896 LOGE("failed to add elements");
3900 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3901 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3902 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3904 /* linking elements in the bucket by added order. */
3905 LOGD("Linking elements in the bucket by added order.");
3906 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3907 LOGE("failed to link elements");
3911 if (textbin[MMPLAYER_T_QUEUE].gst) {
3913 GstPad *ghostpad = NULL;
3915 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3917 LOGE("failed to get sink pad of text queue");
3921 ghostpad = gst_ghost_pad_new("text_sink", pad);
3922 gst_object_unref(pad);
3925 LOGE("failed to create ghostpad of textbin");
3929 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3930 LOGE("failed to add ghostpad to textbin");
3931 gst_object_unref(ghostpad);
3936 g_list_free(element_bucket);
3938 return MM_ERROR_NONE;
3942 g_list_free(element_bucket);
3944 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3945 LOGE("remove textbin sink from sink list");
3946 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3949 /* release element at __mmplayer_gst_create_text_sink_bin */
3950 return MM_ERROR_PLAYER_INTERNAL;
3954 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3956 mmplayer_gst_element_t *textbin = NULL;
3957 int surface_type = 0;
3962 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3965 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3967 LOGE("failed to allocate memory for textbin");
3968 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3972 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3973 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3974 if (!textbin[MMPLAYER_T_BIN].gst) {
3975 LOGE("failed to create textbin");
3980 player->pipeline->textbin = textbin;
3983 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3984 LOGD("surface type for subtitle : %d", surface_type);
3985 switch (surface_type) {
3986 case MM_DISPLAY_SURFACE_OVERLAY:
3987 case MM_DISPLAY_SURFACE_NULL:
3988 case MM_DISPLAY_SURFACE_REMOTE:
3989 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3990 LOGE("failed to make plain text elements");
4001 return MM_ERROR_NONE;
4005 LOGD("ERROR : releasing textbin");
4007 /* release signal */
4008 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4010 /* release element which are not added to bin */
4011 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4012 /* NOTE : skip bin */
4013 if (textbin[i].gst) {
4014 GstObject *parent = NULL;
4015 parent = gst_element_get_parent(textbin[i].gst);
4018 gst_object_unref(GST_OBJECT(textbin[i].gst));
4019 textbin[i].gst = NULL;
4021 gst_object_unref(GST_OBJECT(parent));
4026 /* release textbin with it's children */
4027 if (textbin[MMPLAYER_T_BIN].gst)
4028 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4030 MMPLAYER_FREEIF(textbin);
4031 player->pipeline->textbin = NULL;
4034 return MM_ERROR_PLAYER_INTERNAL;
4038 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4040 mmplayer_gst_element_t *mainbin = NULL;
4041 mmplayer_gst_element_t *textbin = NULL;
4042 MMHandleType attrs = 0;
4043 GstElement *subsrc = NULL;
4044 GstElement *subparse = NULL;
4045 gchar *subtitle_uri = NULL;
4046 const gchar *charset = NULL;
4052 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4054 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4056 mainbin = player->pipeline->mainbin;
4058 attrs = MMPLAYER_GET_ATTRS(player);
4060 LOGE("cannot get content attribute");
4061 return MM_ERROR_PLAYER_INTERNAL;
4064 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4065 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4066 LOGE("subtitle uri is not proper filepath.");
4067 return MM_ERROR_PLAYER_INVALID_URI;
4070 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4071 LOGE("failed to get storage info of subtitle path");
4072 return MM_ERROR_PLAYER_INVALID_URI;
4075 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4077 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4078 player->subtitle_language_list = NULL;
4079 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4081 /* create the subtitle source */
4082 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4084 LOGE("failed to create filesrc element");
4087 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4089 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4090 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4092 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4093 LOGW("failed to add queue");
4094 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4095 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4096 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4101 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4103 LOGE("failed to create subparse element");
4107 charset = _mmplayer_get_charset(subtitle_uri);
4109 LOGD("detected charset is %s", charset);
4110 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4113 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4114 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4116 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4117 LOGW("failed to add subparse");
4118 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4119 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4120 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4124 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4125 LOGW("failed to link subsrc and subparse");
4129 player->play_subtitle = TRUE;
4130 player->adjust_subtitle_pos = 0;
4132 LOGD("play subtitle using subtitle file");
4134 if (player->pipeline->textbin == NULL) {
4135 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4136 LOGE("failed to create text sink bin. continuing without text");
4140 textbin = player->pipeline->textbin;
4142 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4143 LOGW("failed to add textbin");
4145 /* release signal */
4146 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4148 /* release textbin with it's children */
4149 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4150 MMPLAYER_FREEIF(player->pipeline->textbin);
4151 player->pipeline->textbin = textbin = NULL;
4155 LOGD("link text input selector and textbin ghost pad");
4157 player->textsink_linked = 1;
4158 player->external_text_idx = 0;
4159 LOGI("textsink is linked");
4161 textbin = player->pipeline->textbin;
4162 LOGD("text bin has been created. reuse it.");
4163 player->external_text_idx = 1;
4166 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4167 LOGW("failed to link subparse and textbin");
4171 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4173 LOGE("failed to get sink pad from textsink to probe data");
4177 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4178 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4180 gst_object_unref(pad);
4183 /* create dot. for debugging */
4184 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4187 return MM_ERROR_NONE;
4190 /* release text pipeline resource */
4191 player->textsink_linked = 0;
4193 /* release signal */
4194 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4196 if (player->pipeline->textbin) {
4197 LOGE("remove textbin");
4199 /* release textbin with it's children */
4200 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4201 MMPLAYER_FREEIF(player->pipeline->textbin);
4202 player->pipeline->textbin = NULL;
4206 /* release subtitle elem */
4207 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4208 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4210 return MM_ERROR_PLAYER_INTERNAL;
4214 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4216 mmplayer_t *player = (mmplayer_t *)data;
4217 MMMessageParamType msg = {0, };
4218 GstClockTime duration = 0;
4219 gpointer text = NULL;
4220 guint text_size = 0;
4221 gboolean ret = TRUE;
4222 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4226 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4227 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4229 if (player->is_subtitle_force_drop) {
4230 LOGW("subtitle is dropped forcedly.");
4234 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4235 text = mapinfo.data;
4236 text_size = mapinfo.size;
4238 if (player->set_mode.subtitle_off) {
4239 LOGD("subtitle is OFF.");
4243 if (!text || (text_size == 0)) {
4244 LOGD("There is no subtitle to be displayed.");
4248 msg.data = (void *)text;
4250 duration = GST_BUFFER_DURATION(buffer);
4252 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4253 if (player->duration > GST_BUFFER_PTS(buffer))
4254 duration = player->duration - GST_BUFFER_PTS(buffer);
4257 LOGI("subtitle duration is invalid, subtitle duration change "
4258 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4260 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4262 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4264 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4265 gst_buffer_unmap(buffer, &mapinfo);
4272 static GstPadProbeReturn
4273 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4275 mmplayer_t *player = (mmplayer_t *)u_data;
4276 GstClockTime cur_timestamp = 0;
4277 gint64 adjusted_timestamp = 0;
4278 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4280 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4282 if (player->set_mode.subtitle_off) {
4283 LOGD("subtitle is OFF.");
4287 if (player->adjust_subtitle_pos == 0) {
4288 LOGD("nothing to do");
4292 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4293 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4295 if (adjusted_timestamp < 0) {
4296 LOGD("adjusted_timestamp under zero");
4301 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4302 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4303 GST_TIME_ARGS(cur_timestamp),
4304 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4306 return GST_PAD_PROBE_OK;
4310 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4314 /* check player and subtitlebin are created */
4315 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4316 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4318 if (position == 0) {
4319 LOGD("nothing to do");
4321 return MM_ERROR_NONE;
4324 /* check current position */
4325 player->adjust_subtitle_pos = position;
4327 LOGD("save adjust_subtitle_pos in player");
4331 return MM_ERROR_NONE;
4335 * This function is to create audio or video pipeline for playing.
4337 * @param player [in] handle of player
4339 * @return This function returns zero on success.
4344 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4346 int ret = MM_ERROR_NONE;
4347 mmplayer_gst_element_t *mainbin = NULL;
4348 MMHandleType attrs = 0;
4351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4353 /* get profile attribute */
4354 attrs = MMPLAYER_GET_ATTRS(player);
4356 LOGE("failed to get content attribute");
4360 /* create pipeline handles */
4361 if (player->pipeline) {
4362 LOGE("pipeline should be released before create new one");
4366 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4368 /* create mainbin */
4369 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4370 if (mainbin == NULL)
4373 /* create pipeline */
4374 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4375 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4376 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4377 LOGE("failed to create pipeline");
4382 player->pipeline->mainbin = mainbin;
4384 /* create the source and decoder elements */
4385 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4386 ret = _mmplayer_gst_build_es_pipeline(player);
4388 if (MMPLAYER_USE_DECODEBIN(player))
4389 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4391 ret = _mmplayer_gst_build_pipeline_with_src(player);
4394 if (ret != MM_ERROR_NONE) {
4395 LOGE("failed to create some elements");
4399 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4400 if (__mmplayer_check_subtitle(player)
4401 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4402 LOGE("failed to create text pipeline");
4405 ret = _mmplayer_gst_add_bus_watch(player);
4406 if (ret != MM_ERROR_NONE) {
4407 LOGE("failed to add bus watch");
4412 return MM_ERROR_NONE;
4415 _mmplayer_bus_watcher_remove(player);
4416 __mmplayer_gst_destroy_pipeline(player);
4417 return MM_ERROR_PLAYER_INTERNAL;
4421 __mmplayer_reset_gapless_state(mmplayer_t *player)
4424 MMPLAYER_RETURN_IF_FAIL(player
4426 && player->pipeline->audiobin
4427 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4429 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4436 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4439 int ret = MM_ERROR_NONE;
4443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4445 /* cleanup stuffs */
4446 MMPLAYER_FREEIF(player->type_caps_str);
4447 player->no_more_pad = FALSE;
4448 player->num_dynamic_pad = 0;
4450 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4451 player->subtitle_language_list = NULL;
4452 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4454 MMPLAYER_RECONFIGURE_LOCK(player);
4455 __mmplayer_reset_gapless_state(player);
4456 MMPLAYER_RECONFIGURE_UNLOCK(player);
4458 if (player->streamer) {
4459 _mm_player_streaming_initialize(player->streamer, FALSE);
4460 _mm_player_streaming_destroy(player->streamer);
4461 player->streamer = NULL;
4464 /* cleanup unlinked mime type */
4465 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4466 MMPLAYER_FREEIF(player->unlinked_video_mime);
4467 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4469 /* cleanup running stuffs */
4470 _mmplayer_cancel_eos_timer(player);
4472 /* cleanup gst stuffs */
4473 if (player->pipeline) {
4474 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4475 GstTagList *tag_list = player->pipeline->tag_list;
4477 /* first we need to disconnect all signal hander */
4478 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4481 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4482 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4483 gst_object_unref(bus);
4485 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4486 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4487 if (ret != MM_ERROR_NONE) {
4488 LOGE("fail to change state to NULL");
4489 return MM_ERROR_PLAYER_INTERNAL;
4492 LOGW("succeeded in changing state to NULL");
4494 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4497 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4498 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4500 MMPLAYER_FREEIF(player->pipeline->audiobin);
4501 MMPLAYER_FREEIF(player->pipeline->videobin);
4502 MMPLAYER_FREEIF(player->pipeline->textbin);
4503 MMPLAYER_FREEIF(mainbin);
4507 gst_tag_list_unref(tag_list);
4509 MMPLAYER_FREEIF(player->pipeline);
4511 MMPLAYER_FREEIF(player->album_art);
4513 if (player->v_stream_caps) {
4514 gst_caps_unref(player->v_stream_caps);
4515 player->v_stream_caps = NULL;
4518 if (player->a_stream_caps) {
4519 gst_caps_unref(player->a_stream_caps);
4520 player->a_stream_caps = NULL;
4523 if (player->s_stream_caps) {
4524 gst_caps_unref(player->s_stream_caps);
4525 player->s_stream_caps = NULL;
4527 _mmplayer_track_destroy(player);
4529 if (player->sink_elements)
4530 g_list_free(player->sink_elements);
4531 player->sink_elements = NULL;
4533 if (player->bufmgr) {
4534 tbm_bufmgr_deinit(player->bufmgr);
4535 player->bufmgr = NULL;
4538 LOGW("finished destroy pipeline");
4546 __mmplayer_gst_realize(mmplayer_t *player)
4549 int ret = MM_ERROR_NONE;
4553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4555 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4557 ret = __mmplayer_gst_create_pipeline(player);
4559 LOGE("failed to create pipeline");
4563 /* set pipeline state to READY */
4564 /* NOTE : state change to READY must be performed sync. */
4565 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4566 ret = _mmplayer_gst_set_state(player,
4567 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4569 if (ret != MM_ERROR_NONE) {
4570 /* return error if failed to set state */
4571 LOGE("failed to set READY state");
4575 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4577 /* create dot before error-return. for debugging */
4578 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4586 __mmplayer_gst_unrealize(mmplayer_t *player)
4588 int ret = MM_ERROR_NONE;
4592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4594 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4595 MMPLAYER_PRINT_STATE(player);
4597 /* release miscellaneous information */
4598 __mmplayer_release_misc(player);
4600 /* destroy pipeline */
4601 ret = __mmplayer_gst_destroy_pipeline(player);
4602 if (ret != MM_ERROR_NONE) {
4603 LOGE("failed to destroy pipeline");
4607 /* release miscellaneous information.
4608 these info needs to be released after pipeline is destroyed. */
4609 __mmplayer_release_misc_post(player);
4611 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4619 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4624 LOGW("set_message_callback is called with invalid player handle");
4625 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4628 player->msg_cb = callback;
4629 player->msg_cb_param = user_param;
4631 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4635 return MM_ERROR_NONE;
4639 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4641 int ret = MM_ERROR_NONE;
4646 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4647 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4648 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4650 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4652 if (strstr(uri, "es_buff://")) {
4653 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4654 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4655 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4656 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4658 tmp = g_ascii_strdown(uri, strlen(uri));
4659 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4660 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4662 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4664 } else if (strstr(uri, "mms://")) {
4665 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4666 } else if ((path = strstr(uri, "mem://"))) {
4667 ret = __mmplayer_set_mem_uri(data, path, param);
4669 ret = __mmplayer_set_file_uri(data, uri);
4672 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4673 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4674 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4675 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4677 /* dump parse result */
4678 SECURE_LOGW("incoming uri : %s", uri);
4679 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4680 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4688 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4691 mmplayer_t *player = NULL;
4692 MMMessageParamType msg = {0, };
4694 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4699 LOGE("user_data is null");
4703 player = (mmplayer_t *)user_data;
4705 if (!player->pipeline || !player->attrs) {
4706 LOGW("not initialized");
4710 LOGD("cmd lock player, cmd state : %d", player->cmd);
4711 MMPLAYER_CMD_LOCK(player);
4712 LOGD("cmd locked player");
4714 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4715 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4716 LOGW("player already destroyed");
4717 MMPLAYER_CMD_UNLOCK(player);
4721 player->interrupted_by_resource = TRUE;
4723 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4725 /* get last play position */
4726 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4727 msg.union_type = MM_MSG_UNION_TIME;
4728 msg.time.elapsed = pos;
4729 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4731 LOGW("failed to get play position.");
4734 LOGD("video resource conflict so, resource will be freed by unrealizing");
4735 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4736 LOGE("failed to unrealize");
4738 MMPLAYER_CMD_UNLOCK(player);
4740 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4741 player->hw_resource[res_idx] = NULL;
4745 return TRUE; /* release all the resources */
4749 __mmplayer_initialize_video_roi(mmplayer_t *player)
4751 player->video_roi.scale_x = 0.0;
4752 player->video_roi.scale_y = 0.0;
4753 player->video_roi.scale_width = 1.0;
4754 player->video_roi.scale_height = 1.0;
4758 _mmplayer_create_player(MMHandleType handle)
4760 int ret = MM_ERROR_PLAYER_INTERNAL;
4761 bool enabled = false;
4763 mmplayer_t *player = MM_PLAYER_CAST(handle);
4767 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4769 /* initialize player state */
4770 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4771 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4772 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4773 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4775 /* check current state */
4776 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4778 /* construct attributes */
4779 player->attrs = _mmplayer_construct_attribute(handle);
4781 if (!player->attrs) {
4782 LOGE("Failed to construct attributes");
4786 /* initialize gstreamer with configured parameter */
4787 if (!__mmplayer_init_gstreamer(player)) {
4788 LOGE("Initializing gstreamer failed");
4789 _mmplayer_deconstruct_attribute(handle);
4793 /* create lock. note that g_tread_init() has already called in gst_init() */
4794 g_mutex_init(&player->fsink_lock);
4796 /* create update tag lock */
4797 g_mutex_init(&player->update_tag_lock);
4799 /* create gapless play mutex */
4800 g_mutex_init(&player->gapless_play_thread_mutex);
4802 /* create gapless play cond */
4803 g_cond_init(&player->gapless_play_thread_cond);
4805 /* create gapless play thread */
4806 player->gapless_play_thread =
4807 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4808 if (!player->gapless_play_thread) {
4809 LOGE("failed to create gapless play thread");
4810 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4811 g_mutex_clear(&player->gapless_play_thread_mutex);
4812 g_cond_clear(&player->gapless_play_thread_cond);
4816 player->bus_msg_q = g_queue_new();
4817 if (!player->bus_msg_q) {
4818 LOGE("failed to create queue for bus_msg");
4819 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4823 ret = _mmplayer_initialize_video_capture(player);
4824 if (ret != MM_ERROR_NONE) {
4825 LOGW("video capture is not supported");
4826 /* do not handle as error for headless profile */
4829 /* initialize resource manager */
4830 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4831 __resource_release_cb, player, &player->resource_manager)
4832 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4833 LOGE("failed to create resource manager");
4834 ret = MM_ERROR_PLAYER_INTERNAL;
4838 /* create video bo lock and cond */
4839 g_mutex_init(&player->video_bo_mutex);
4840 g_cond_init(&player->video_bo_cond);
4842 /* create subtitle info lock and cond */
4843 g_mutex_init(&player->subtitle_info_mutex);
4844 g_cond_init(&player->subtitle_info_cond);
4846 player->streaming_type = STREAMING_SERVICE_NONE;
4848 /* give default value of audio effect setting */
4849 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4850 player->sound.rg_enable = false;
4851 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4853 player->play_subtitle = FALSE;
4854 player->has_closed_caption = FALSE;
4855 player->pending_resume = FALSE;
4856 if (player->ini.dump_element_keyword[0][0] == '\0')
4857 player->ini.set_dump_element_flag = FALSE;
4859 player->ini.set_dump_element_flag = TRUE;
4861 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4862 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4863 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4865 /* Set video360 settings to their defaults for just-created player.
4868 player->is_360_feature_enabled = FALSE;
4869 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4870 LOGI("spherical feature info: %d", enabled);
4872 player->is_360_feature_enabled = TRUE;
4874 LOGE("failed to get spherical feature info");
4877 player->is_content_spherical = FALSE;
4878 player->is_video360_enabled = TRUE;
4879 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4880 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4881 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4882 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4883 player->video360_zoom = 1.0f;
4884 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4885 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4887 __mmplayer_initialize_video_roi(player);
4889 /* set player state to null */
4890 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4891 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4895 return MM_ERROR_NONE;
4899 g_mutex_clear(&player->fsink_lock);
4900 /* free update tag lock */
4901 g_mutex_clear(&player->update_tag_lock);
4902 g_queue_free(player->bus_msg_q);
4903 player->bus_msg_q = NULL;
4904 /* free gapless play thread */
4905 if (player->gapless_play_thread) {
4906 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4907 player->gapless_play_thread_exit = TRUE;
4908 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4909 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4911 g_thread_join(player->gapless_play_thread);
4912 player->gapless_play_thread = NULL;
4914 g_mutex_clear(&player->gapless_play_thread_mutex);
4915 g_cond_clear(&player->gapless_play_thread_cond);
4918 /* release attributes */
4919 _mmplayer_deconstruct_attribute(handle);
4927 __mmplayer_init_gstreamer(mmplayer_t *player)
4929 static gboolean initialized = FALSE;
4930 static const int max_argc = 50;
4932 gchar **argv = NULL;
4933 gchar **argv2 = NULL;
4939 LOGD("gstreamer already initialized.");
4944 argc = malloc(sizeof(int));
4945 argv = malloc(sizeof(gchar *) * max_argc);
4946 argv2 = malloc(sizeof(gchar *) * max_argc);
4948 if (!argc || !argv || !argv2)
4951 memset(argv, 0, sizeof(gchar *) * max_argc);
4952 memset(argv2, 0, sizeof(gchar *) * max_argc);
4956 argv[0] = g_strdup("mmplayer");
4959 for (i = 0; i < 5; i++) {
4960 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4961 if (strlen(player->ini.gst_param[i]) > 0) {
4962 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4967 /* we would not do fork for scanning plugins */
4968 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4971 /* check disable registry scan */
4972 if (player->ini.skip_rescan) {
4973 argv[*argc] = g_strdup("--gst-disable-registry-update");
4977 /* check disable segtrap */
4978 if (player->ini.disable_segtrap) {
4979 argv[*argc] = g_strdup("--gst-disable-segtrap");
4983 LOGD("initializing gstreamer with following parameter");
4984 LOGD("argc : %d", *argc);
4987 for (i = 0; i < arg_count; i++) {
4989 LOGD("argv[%d] : %s", i, argv2[i]);
4992 /* initializing gstreamer */
4993 if (!gst_init_check(argc, &argv, &err)) {
4994 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
5001 for (i = 0; i < arg_count; i++) {
5003 LOGD("release - argv[%d] : %s", i, argv2[i]);
5005 MMPLAYER_FREEIF(argv2[i]);
5008 MMPLAYER_FREEIF(argv);
5009 MMPLAYER_FREEIF(argv2);
5010 MMPLAYER_FREEIF(argc);
5020 for (i = 0; i < arg_count; i++) {
5021 LOGD("free[%d] : %s", i, argv2[i]);
5022 MMPLAYER_FREEIF(argv2[i]);
5025 MMPLAYER_FREEIF(argv);
5026 MMPLAYER_FREEIF(argv2);
5027 MMPLAYER_FREEIF(argc);
5033 __mmplayer_check_async_state_transition(mmplayer_t *player)
5035 GstState element_state = GST_STATE_VOID_PENDING;
5036 GstState element_pending_state = GST_STATE_VOID_PENDING;
5037 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5038 GstElement *element = NULL;
5039 gboolean async = FALSE;
5041 /* check player handle */
5042 MMPLAYER_RETURN_IF_FAIL(player &&
5044 player->pipeline->mainbin &&
5045 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5048 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5050 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5051 LOGD("don't need to check the pipeline state");
5055 MMPLAYER_PRINT_STATE(player);
5057 /* wait for state transition */
5058 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5059 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5061 if (ret == GST_STATE_CHANGE_FAILURE) {
5062 LOGE(" [%s] state : %s pending : %s",
5063 GST_ELEMENT_NAME(element),
5064 gst_element_state_get_name(element_state),
5065 gst_element_state_get_name(element_pending_state));
5067 /* dump state of all element */
5068 _mmplayer_dump_pipeline_state(player);
5073 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5078 _mmplayer_destroy(MMHandleType handle)
5080 mmplayer_t *player = MM_PLAYER_CAST(handle);
5084 /* check player handle */
5085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5087 /* destroy can called at anytime */
5088 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5090 /* check async state transition */
5091 __mmplayer_check_async_state_transition(player);
5093 /* release gapless play thread */
5094 if (player->gapless_play_thread) {
5095 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5096 player->gapless_play_thread_exit = TRUE;
5097 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5098 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5100 LOGD("waiting for gapless play thread exit");
5101 g_thread_join(player->gapless_play_thread);
5102 g_mutex_clear(&player->gapless_play_thread_mutex);
5103 g_cond_clear(&player->gapless_play_thread_cond);
5104 LOGD("gapless play thread released");
5107 _mmplayer_release_video_capture(player);
5109 /* release miscellaneous information */
5110 __mmplayer_release_misc(player);
5112 /* release pipeline */
5113 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5114 LOGE("failed to destroy pipeline");
5115 return MM_ERROR_PLAYER_INTERNAL;
5118 __mmplayer_destroy_hw_resource(player);
5120 g_queue_free(player->bus_msg_q);
5122 /* release subtitle info lock and cond */
5123 g_mutex_clear(&player->subtitle_info_mutex);
5124 g_cond_clear(&player->subtitle_info_cond);
5126 __mmplayer_release_dump_list(player->dump_list);
5128 /* release miscellaneous information.
5129 these info needs to be released after pipeline is destroyed. */
5130 __mmplayer_release_misc_post(player);
5132 /* release attributes */
5133 _mmplayer_deconstruct_attribute(handle);
5135 if (player->uri_info.uri_list) {
5136 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5137 player->uri_info.uri_list = NULL;
5141 g_mutex_clear(&player->fsink_lock);
5144 g_mutex_clear(&player->update_tag_lock);
5146 /* release video bo lock and cond */
5147 g_mutex_clear(&player->video_bo_mutex);
5148 g_cond_clear(&player->video_bo_cond);
5152 return MM_ERROR_NONE;
5156 _mmplayer_realize(MMHandleType hplayer)
5158 mmplayer_t *player = (mmplayer_t *)hplayer;
5159 int ret = MM_ERROR_NONE;
5162 MMHandleType attrs = 0;
5166 /* check player handle */
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 /* check current state */
5170 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5172 attrs = MMPLAYER_GET_ATTRS(player);
5174 LOGE("fail to get attributes.");
5175 return MM_ERROR_PLAYER_INTERNAL;
5177 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5178 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5180 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5181 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5183 if (ret != MM_ERROR_NONE) {
5184 LOGE("failed to parse profile");
5189 if (uri && (strstr(uri, "es_buff://"))) {
5190 if (strstr(uri, "es_buff://push_mode"))
5191 player->es_player_push_mode = TRUE;
5193 player->es_player_push_mode = FALSE;
5196 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5197 LOGW("mms protocol is not supported format.");
5198 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5201 if (MMPLAYER_IS_STREAMING(player))
5202 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5204 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5206 player->smooth_streaming = FALSE;
5207 player->videodec_linked = 0;
5208 player->audiodec_linked = 0;
5209 player->textsink_linked = 0;
5210 player->is_external_subtitle_present = FALSE;
5211 player->is_external_subtitle_added_now = FALSE;
5212 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5213 player->video360_metadata.is_spherical = -1;
5214 player->is_openal_plugin_used = FALSE;
5215 player->subtitle_language_list = NULL;
5216 player->is_subtitle_force_drop = FALSE;
5218 _mmplayer_track_initialize(player);
5219 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5221 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5222 gint prebuffer_ms = 0, rebuffer_ms = 0;
5224 player->streamer = _mm_player_streaming_create();
5225 _mm_player_streaming_initialize(player->streamer, TRUE);
5227 mm_attrs_multiple_get(player->attrs, NULL,
5228 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5229 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5231 if (prebuffer_ms > 0) {
5232 prebuffer_ms = MAX(prebuffer_ms, 1000);
5233 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5236 if (rebuffer_ms > 0) {
5237 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5238 rebuffer_ms = MAX(rebuffer_ms, 1000);
5239 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5242 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5243 player->streamer->buffering_req.rebuffer_time);
5246 /* realize pipeline */
5247 ret = __mmplayer_gst_realize(player);
5248 if (ret != MM_ERROR_NONE)
5249 LOGE("fail to realize the player.");
5251 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5259 _mmplayer_unrealize(MMHandleType hplayer)
5261 mmplayer_t *player = (mmplayer_t *)hplayer;
5262 int ret = MM_ERROR_NONE;
5263 int rm_ret = MM_ERROR_NONE;
5264 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 MMPLAYER_CMD_UNLOCK(player);
5271 _mmplayer_bus_watcher_remove(player);
5272 /* destroy the gst bus msg thread which is created during realize.
5273 this funct have to be called before getting cmd lock. */
5274 _mmplayer_bus_msg_thread_destroy(player);
5275 MMPLAYER_CMD_LOCK(player);
5277 /* check current state */
5278 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5280 /* check async state transition */
5281 __mmplayer_check_async_state_transition(player);
5283 /* unrealize pipeline */
5284 ret = __mmplayer_gst_unrealize(player);
5286 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5287 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5288 if (rm_ret != MM_ERROR_NONE)
5289 LOGE("failed to release [%d] resources", res_idx);
5292 player->interrupted_by_resource = FALSE;
5299 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5301 mmplayer_t *player = (mmplayer_t *)hplayer;
5303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5305 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5309 _mmplayer_get_state(MMHandleType hplayer, int *state)
5311 mmplayer_t *player = (mmplayer_t *)hplayer;
5313 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5315 *state = MMPLAYER_CURRENT_STATE(player);
5317 return MM_ERROR_NONE;
5321 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5323 GstElement *vol_element = NULL;
5324 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5328 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5330 /* check pipeline handle */
5331 if (!player->pipeline || !player->pipeline->audiobin) {
5332 LOGD("'%s' will be applied when audiobin is created", prop_name);
5334 /* NOTE : stored value will be used in create_audiobin
5335 * returning MM_ERROR_NONE here makes application to able to
5336 * set audio volume or mute at anytime.
5338 return MM_ERROR_NONE;
5341 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5342 volume_elem_id = MMPLAYER_A_SINK;
5344 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5346 LOGE("failed to get vol element %d", volume_elem_id);
5347 return MM_ERROR_PLAYER_INTERNAL;
5350 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5352 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5353 LOGE("there is no '%s' property", prop_name);
5354 return MM_ERROR_PLAYER_INTERNAL;
5357 if (!strcmp(prop_name, "volume")) {
5358 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5359 } else if (!strcmp(prop_name, "mute")) {
5360 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5362 LOGE("invalid property %s", prop_name);
5363 return MM_ERROR_PLAYER_INTERNAL;
5366 return MM_ERROR_NONE;
5370 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5372 int ret = MM_ERROR_NONE;
5373 mmplayer_t *player = (mmplayer_t *)hplayer;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 LOGD("volume = %f", volume);
5380 /* invalid factor range or not */
5381 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5382 LOGE("Invalid volume value");
5383 return MM_ERROR_INVALID_ARGUMENT;
5386 player->sound.volume = volume;
5388 ret = __mmplayer_gst_set_volume_property(player, "volume");
5395 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5397 mmplayer_t *player = (mmplayer_t *)hplayer;
5401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5402 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5404 *volume = player->sound.volume;
5406 LOGD("current vol = %f", *volume);
5409 return MM_ERROR_NONE;
5413 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5415 int ret = MM_ERROR_NONE;
5416 mmplayer_t *player = (mmplayer_t *)hplayer;
5419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421 LOGD("mute = %d", mute);
5423 player->sound.mute = mute;
5425 ret = __mmplayer_gst_set_volume_property(player, "mute");
5432 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5434 mmplayer_t *player = (mmplayer_t *)hplayer;
5438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5439 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5441 *mute = player->sound.mute;
5443 LOGD("current mute = %d", *mute);
5447 return MM_ERROR_NONE;
5451 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5453 mmplayer_t *player = (mmplayer_t *)hplayer;
5457 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459 player->audio_stream_changed_cb = callback;
5460 player->audio_stream_changed_cb_user_param = user_param;
5461 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5465 return MM_ERROR_NONE;
5469 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5471 mmplayer_t *player = (mmplayer_t *)hplayer;
5475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5477 player->audio_decoded_cb = callback;
5478 player->audio_decoded_cb_user_param = user_param;
5479 player->audio_extract_opt = opt;
5480 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5484 return MM_ERROR_NONE;
5488 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5490 mmplayer_t *player = (mmplayer_t *)hplayer;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 if (callback && !player->bufmgr)
5497 player->bufmgr = tbm_bufmgr_init(-1);
5499 player->set_mode.video_export = (callback) ? true : false;
5500 player->video_decoded_cb = callback;
5501 player->video_decoded_cb_user_param = user_param;
5503 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5507 return MM_ERROR_NONE;
5511 _mmplayer_start(MMHandleType hplayer)
5513 mmplayer_t *player = (mmplayer_t *)hplayer;
5514 gint ret = MM_ERROR_NONE;
5518 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5520 /* check current state */
5521 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5523 /* start pipeline */
5524 ret = _mmplayer_gst_start(player);
5525 if (ret != MM_ERROR_NONE)
5526 LOGE("failed to start player.");
5528 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5529 LOGD("force playing start even during buffering");
5530 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5538 /* NOTE: post "not supported codec message" to application
5539 * when one codec is not found during AUTOPLUGGING in MSL.
5540 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5541 * And, if any codec is not found, don't send message here.
5542 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5545 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5547 MMMessageParamType msg_param;
5548 memset(&msg_param, 0, sizeof(MMMessageParamType));
5549 gboolean post_msg_direct = FALSE;
5553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5555 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5556 player->not_supported_codec, player->can_support_codec);
5558 if (player->not_found_demuxer) {
5559 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5560 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5562 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5563 MMPLAYER_FREEIF(msg_param.data);
5565 return MM_ERROR_NONE;
5568 if (player->not_supported_codec) {
5569 if (player->can_support_codec) {
5570 // There is one codec to play
5571 post_msg_direct = TRUE;
5573 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5574 post_msg_direct = TRUE;
5577 if (post_msg_direct) {
5578 MMMessageParamType msg_param;
5579 memset(&msg_param, 0, sizeof(MMMessageParamType));
5581 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5582 LOGW("not found AUDIO codec, posting error code to application.");
5584 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5585 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5586 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5587 LOGW("not found VIDEO codec, posting error code to application.");
5589 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5590 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5593 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5595 MMPLAYER_FREEIF(msg_param.data);
5597 return MM_ERROR_NONE;
5599 // no any supported codec case
5600 LOGW("not found any codec, posting error code to application.");
5602 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5603 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5604 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5606 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5607 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5610 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5612 MMPLAYER_FREEIF(msg_param.data);
5618 return MM_ERROR_NONE;
5621 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5623 GstState element_state = GST_STATE_VOID_PENDING;
5624 GstState element_pending_state = GST_STATE_VOID_PENDING;
5625 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5626 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5628 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5630 MMPLAYER_RECONFIGURE_LOCK(player);
5631 if (!player->gapless.reconfigure) {
5632 MMPLAYER_RECONFIGURE_UNLOCK(player);
5636 LOGI("reconfigure is under process");
5637 MMPLAYER_RECONFIGURE_WAIT(player);
5638 MMPLAYER_RECONFIGURE_UNLOCK(player);
5639 LOGI("reconfigure is completed.");
5641 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5642 &element_state, &element_pending_state, timeout * GST_SECOND);
5643 if (result == GST_STATE_CHANGE_FAILURE)
5644 LOGW("failed to get pipeline state in %d sec", timeout);
5649 /* NOTE : it should be able to call 'stop' anytime*/
5651 _mmplayer_stop(MMHandleType hplayer)
5653 mmplayer_t *player = (mmplayer_t *)hplayer;
5654 int ret = MM_ERROR_NONE;
5658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5660 /* check current state */
5661 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5663 /* need to wait till the rebuilding pipeline is completed */
5664 __mmplayer_check_pipeline_reconfigure_state(player);
5665 MMPLAYER_RECONFIGURE_LOCK(player);
5666 __mmplayer_reset_gapless_state(player);
5667 MMPLAYER_RECONFIGURE_UNLOCK(player);
5669 /* NOTE : application should not wait for EOS after calling STOP */
5670 _mmplayer_cancel_eos_timer(player);
5673 player->seek_state = MMPLAYER_SEEK_NONE;
5676 ret = _mmplayer_gst_stop(player);
5678 if (ret != MM_ERROR_NONE)
5679 LOGE("failed to stop player.");
5687 _mmplayer_pause(MMHandleType hplayer)
5689 mmplayer_t *player = (mmplayer_t *)hplayer;
5690 gint64 pos_nsec = 0;
5691 gboolean async = FALSE;
5692 gint ret = MM_ERROR_NONE;
5696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5698 /* check current state */
5699 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5701 /* check pipeline reconfigure state */
5702 __mmplayer_check_pipeline_reconfigure_state(player);
5704 switch (MMPLAYER_CURRENT_STATE(player)) {
5705 case MM_PLAYER_STATE_READY:
5707 /* check prepare async or not.
5708 * In the case of streaming playback, it's recommended to avoid blocking wait.
5710 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5711 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5713 /* Changing back sync of rtspsrc to async */
5714 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5715 LOGD("async prepare working mode for rtsp");
5721 case MM_PLAYER_STATE_PLAYING:
5723 /* NOTE : store current point to overcome some bad operation
5724 *(returning zero when getting current position in paused state) of some
5727 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5728 LOGW("getting current position failed in paused");
5730 player->last_position = pos_nsec;
5732 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5733 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5734 This causes problem is position calculation during normal pause resume scenarios also.
5735 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5736 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5737 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5738 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5744 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5745 LOGD("doing async pause in case of ms buff src");
5749 /* pause pipeline */
5750 ret = _mmplayer_gst_pause(player, async);
5751 if (ret != MM_ERROR_NONE) {
5752 LOGE("failed to pause player. ret : 0x%x", ret);
5753 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5757 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5758 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5759 LOGE("failed to update display_rotation");
5763 return MM_ERROR_NONE;
5766 /* in case of streaming, pause could take long time.*/
5768 _mmplayer_abort_pause(MMHandleType hplayer)
5770 mmplayer_t *player = (mmplayer_t *)hplayer;
5771 int ret = MM_ERROR_NONE;
5775 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5777 player->pipeline->mainbin,
5778 MM_ERROR_PLAYER_NOT_INITIALIZED);
5780 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5781 LOGD("set the videobin state to READY");
5782 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5783 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5787 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5788 LOGD("set the audiobin state to READY");
5789 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5790 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5794 LOGD("set the pipeline state to READY");
5795 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5796 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5798 if (ret != MM_ERROR_NONE) {
5799 LOGE("fail to change state to READY");
5800 return MM_ERROR_PLAYER_INTERNAL;
5803 LOGD("succeeded in changing state to READY");
5808 _mmplayer_resume(MMHandleType hplayer)
5810 mmplayer_t *player = (mmplayer_t *)hplayer;
5811 int ret = MM_ERROR_NONE;
5812 gboolean async = FALSE;
5816 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5818 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5819 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5820 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5824 /* Changing back sync mode rtspsrc to async */
5825 LOGD("async resume for rtsp case");
5829 /* check current state */
5830 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5832 ret = _mmplayer_gst_resume(player, async);
5833 if (ret != MM_ERROR_NONE)
5834 LOGE("failed to resume player.");
5836 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5837 LOGD("force resume even during buffering");
5838 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5847 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5849 mmplayer_t *player = (mmplayer_t *)hplayer;
5850 gint64 pos_nsec = 0;
5851 int ret = MM_ERROR_NONE;
5853 signed long long start = 0, stop = 0;
5854 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5857 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5858 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5860 /* The sound of video is not supported under 0.0 and over 2.0. */
5861 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5862 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5865 _mmplayer_set_mute(hplayer, mute);
5867 if (player->playback_rate == rate)
5868 return MM_ERROR_NONE;
5870 /* If the position is reached at start potion during fast backward, EOS is posted.
5871 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5873 player->playback_rate = rate;
5875 current_state = MMPLAYER_CURRENT_STATE(player);
5877 if (current_state != MM_PLAYER_STATE_PAUSED)
5878 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5880 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5882 if ((current_state == MM_PLAYER_STATE_PAUSED)
5883 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5884 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5885 pos_nsec = player->last_position;
5890 stop = GST_CLOCK_TIME_NONE;
5892 start = GST_CLOCK_TIME_NONE;
5896 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5897 player->playback_rate,
5899 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5900 GST_SEEK_TYPE_SET, start,
5901 GST_SEEK_TYPE_SET, stop)) {
5902 LOGE("failed to set speed playback");
5903 return MM_ERROR_PLAYER_SEEK;
5906 LOGD("succeeded to set speed playback as %0.1f", rate);
5910 return MM_ERROR_NONE;;
5914 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5916 mmplayer_t *player = (mmplayer_t *)hplayer;
5917 int ret = MM_ERROR_NONE;
5921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5923 /* check pipeline reconfigure state */
5924 __mmplayer_check_pipeline_reconfigure_state(player);
5926 ret = _mmplayer_gst_set_position(player, position, FALSE);
5934 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5936 mmplayer_t *player = (mmplayer_t *)hplayer;
5937 int ret = MM_ERROR_NONE;
5939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5940 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5942 if (g_strrstr(player->type_caps_str, "video/mpegts"))
5943 __mmplayer_update_duration_value(player);
5945 *duration = player->duration;
5950 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5952 mmplayer_t *player = (mmplayer_t *)hplayer;
5953 int ret = MM_ERROR_NONE;
5955 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5957 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5963 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5965 mmplayer_t *player = (mmplayer_t *)hplayer;
5966 int ret = MM_ERROR_NONE;
5970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5972 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5980 __mmplayer_is_midi_type(gchar *str_caps)
5982 if ((g_strrstr(str_caps, "audio/midi")) ||
5983 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5984 (g_strrstr(str_caps, "application/x-smaf")) ||
5985 (g_strrstr(str_caps, "audio/x-imelody")) ||
5986 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5987 (g_strrstr(str_caps, "audio/xmf")) ||
5988 (g_strrstr(str_caps, "audio/mxmf"))) {
5997 __mmplayer_is_only_mp3_type(gchar *str_caps)
5999 if (g_strrstr(str_caps, "application/x-id3") ||
6000 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
6006 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
6008 GstStructure *caps_structure = NULL;
6009 gint samplerate = 0;
6013 MMPLAYER_RETURN_IF_FAIL(player && caps);
6015 caps_structure = gst_caps_get_structure(caps, 0);
6017 /* set stream information */
6018 gst_structure_get_int(caps_structure, "rate", &samplerate);
6019 gst_structure_get_int(caps_structure, "channels", &channels);
6021 mm_player_set_attribute((MMHandleType)player, NULL,
6022 "content_audio_samplerate", samplerate,
6023 "content_audio_channels", channels, NULL);
6025 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6029 __mmplayer_update_content_type_info(mmplayer_t *player)
6032 MMPLAYER_RETURN_IF_FAIL(player && player->type_caps_str);
6034 if (__mmplayer_is_midi_type(player->type_caps_str)) {
6035 player->bypass_audio_effect = TRUE;
6039 if (!player->streamer) {
6040 LOGD("no need to check streaming type");
6044 if (g_strrstr(player->type_caps_str, "application/x-hls")) {
6045 /* If it can't know exact type when it parses uri because of redirection case,
6046 * it will be fixed by typefinder or when doing autoplugging.
6048 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6049 player->streamer->is_adaptive_streaming = TRUE;
6050 } else if (g_strrstr(player->type_caps_str, "application/dash+xml")) {
6051 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6052 player->streamer->is_adaptive_streaming = TRUE;
6055 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6056 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type_caps_str, "video/mpegts"))) {
6057 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6059 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6060 if (player->streamer->is_adaptive_streaming)
6061 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6063 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6067 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6072 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6073 GstCaps *caps, gpointer data)
6075 mmplayer_t *player = (mmplayer_t *)data;
6079 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6081 MMPLAYER_FREEIF(player->type_caps_str);
6082 player->type_caps_str = gst_caps_to_string(caps);
6083 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6084 player, player->type_caps_str, probability, gst_caps_get_size(caps));
6086 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6087 (g_strrstr(player->type_caps_str, "audio/x-raw-int"))) {
6088 LOGE("not support media format");
6090 if (player->msg_posted == FALSE) {
6091 MMMessageParamType msg_param;
6092 memset(&msg_param, 0, sizeof(MMMessageParamType));
6094 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6095 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6097 /* don't post more if one was sent already */
6098 player->msg_posted = TRUE;
6103 __mmplayer_update_content_type_info(player);
6105 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6108 pad = gst_element_get_static_pad(tf, "src");
6110 LOGE("fail to get typefind src pad.");
6114 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6115 gboolean async = FALSE;
6116 LOGE("failed to autoplug %s", player->type_caps_str);
6118 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6120 if (async && player->msg_posted == FALSE)
6121 __mmplayer_handle_missed_plugin(player);
6123 gst_object_unref(GST_OBJECT(pad));
6130 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6132 GstElement *decodebin = NULL;
6136 /* create decodebin */
6137 decodebin = gst_element_factory_make("decodebin", NULL);
6140 LOGE("fail to create decodebin");
6144 /* raw pad handling signal */
6145 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6146 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6148 /* no-more-pad pad handling signal */
6149 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6150 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6152 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6153 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6155 /* This signal is emitted when a pad for which there is no further possible
6156 decoding is added to the decodebin.*/
6157 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6158 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6160 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6161 before looking for any elements that can handle that stream.*/
6162 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6163 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6165 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6166 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6167 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6169 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6170 before looking for any elements that can handle that stream.*/
6171 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6172 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6174 /* This signal is emitted once decodebin has finished decoding all the data.*/
6175 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6176 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6178 /* This signal is emitted when a element is added to the bin.*/
6179 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6180 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6187 __mmplayer_gst_make_queue2(mmplayer_t *player)
6189 GstElement *queue2 = NULL;
6190 gint64 dur_bytes = 0L;
6191 mmplayer_gst_element_t *mainbin = NULL;
6192 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6195 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6197 mainbin = player->pipeline->mainbin;
6199 queue2 = gst_element_factory_make("queue2", "queue2");
6201 LOGE("failed to create buffering queue element");
6205 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6206 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6208 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6210 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6211 * skip the pull mode(file or ring buffering) setting. */
6212 if (dur_bytes > 0) {
6213 if (!g_strrstr(player->type_caps_str, "video/mpegts")) {
6214 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6215 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6221 _mm_player_streaming_set_queue2(player->streamer,
6225 (guint64)dur_bytes); /* no meaning at the moment */
6231 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6233 mmplayer_gst_element_t *mainbin = NULL;
6234 GstElement *decodebin = NULL;
6235 GstElement *queue2 = NULL;
6236 GstPad *sinkpad = NULL;
6237 GstPad *qsrcpad = NULL;
6240 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6242 mainbin = player->pipeline->mainbin;
6244 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6246 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6247 LOGW("need to check: muxed buffer is not null");
6250 queue2 = __mmplayer_gst_make_queue2(player);
6252 LOGE("failed to make queue2");
6256 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6257 LOGE("failed to add buffering queue");
6261 sinkpad = gst_element_get_static_pad(queue2, "sink");
6262 qsrcpad = gst_element_get_static_pad(queue2, "src");
6264 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6265 LOGE("failed to link [%s:%s]-[%s:%s]",
6266 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6270 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6271 LOGE("failed to sync queue2 state with parent");
6275 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6276 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6280 gst_object_unref(GST_OBJECT(sinkpad));
6284 /* create decodebin */
6285 decodebin = _mmplayer_gst_make_decodebin(player);
6287 LOGE("failed to make decodebin");
6291 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6292 LOGE("failed to add decodebin");
6296 /* to force caps on the decodebin element and avoid reparsing stuff by
6297 * typefind. It also avoids a deadlock in the way typefind activates pads in
6298 * the state change */
6299 g_object_set(decodebin, "sink-caps", caps, NULL);
6301 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6303 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6304 LOGE("failed to link [%s:%s]-[%s:%s]",
6305 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6309 gst_object_unref(GST_OBJECT(sinkpad));
6311 gst_object_unref(GST_OBJECT(qsrcpad));
6314 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6315 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6317 /* set decodebin property about buffer in streaming playback. *
6318 * in case of HLS/DASH, it does not need to have big buffer *
6319 * because it is kind of adaptive streaming. */
6320 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6321 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6322 gint high_percent = 0;
6324 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6325 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6327 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6329 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6331 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6332 "high-percent", high_percent,
6333 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6334 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6335 "max-size-buffers", 0, NULL); // disable or automatic
6338 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6339 LOGE("failed to sync decodebin state with parent");
6350 gst_object_unref(GST_OBJECT(sinkpad));
6353 gst_object_unref(GST_OBJECT(qsrcpad));
6356 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6357 * You need to explicitly set elements to the NULL state before
6358 * dropping the final reference, to allow them to clean up.
6360 gst_element_set_state(queue2, GST_STATE_NULL);
6362 /* And, it still has a parent "player".
6363 * You need to let the parent manage the object instead of unreffing the object directly.
6365 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6366 LOGE("failed to remove queue2");
6367 gst_object_unref(queue2);
6373 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6374 * You need to explicitly set elements to the NULL state before
6375 * dropping the final reference, to allow them to clean up.
6377 gst_element_set_state(decodebin, GST_STATE_NULL);
6379 /* And, it still has a parent "player".
6380 * You need to let the parent manage the object instead of unreffing the object directly.
6383 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6384 LOGE("failed to remove decodebin");
6385 gst_object_unref(decodebin);
6394 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6398 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6399 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6401 LOGD("class : %s, mime : %s", factory_class, mime);
6403 /* add missing plugin */
6404 /* NOTE : msl should check missing plugin for image mime type.
6405 * Some motion jpeg clips can have playable audio track.
6406 * So, msl have to play audio after displaying popup written video format not supported.
6408 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6409 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6410 LOGD("not found demuxer");
6411 player->not_found_demuxer = TRUE;
6412 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6418 if (!g_strrstr(factory_class, "Demuxer")) {
6419 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6420 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6421 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6423 /* check that clip have multi tracks or not */
6424 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6425 LOGD("video plugin is already linked");
6427 LOGW("add VIDEO to missing plugin");
6428 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6429 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6431 } else if (g_str_has_prefix(mime, "audio")) {
6432 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6433 LOGD("audio plugin is already linked");
6435 LOGW("add AUDIO to missing plugin");
6436 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6437 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6445 return MM_ERROR_NONE;
6449 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6451 mmplayer_t *player = (mmplayer_t *)data;
6455 MMPLAYER_RETURN_IF_FAIL(player);
6457 /* remove fakesink. */
6458 if (!_mmplayer_gst_remove_fakesink(player,
6459 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6460 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6461 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6462 * source element are not same. To overcome this situation, this function will called
6463 * several places and several times. Therefore, this is not an error case.
6468 LOGD("[handle: %p] pipeline has completely constructed", player);
6470 if ((player->msg_posted == FALSE) &&
6471 (player->cmd >= MMPLAYER_COMMAND_START))
6472 __mmplayer_handle_missed_plugin(player);
6474 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6478 __mmplayer_check_profile(void)
6481 static int profile_tv = -1;
6483 if (__builtin_expect(profile_tv != -1, 1))
6486 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6487 switch (*profileName) {
6502 __mmplayer_get_next_uri(mmplayer_t *player)
6504 mmplayer_parse_profile_t profile;
6506 guint num_of_list = 0;
6509 num_of_list = g_list_length(player->uri_info.uri_list);
6510 uri_idx = player->uri_info.uri_idx;
6512 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6513 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6514 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6516 LOGW("next uri does not exist");
6520 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6521 LOGE("failed to parse profile");
6525 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6526 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6527 LOGW("uri type is not supported(%d)", profile.uri_type);
6531 LOGD("success to find next uri %d", uri_idx);
6535 if (!uri || uri_idx == num_of_list) {
6536 LOGE("failed to find next uri");
6540 player->uri_info.uri_idx = uri_idx;
6541 if (mm_player_set_attribute((MMHandleType)player, NULL,
6542 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6543 LOGE("failed to set attribute");
6547 if (!MMPLAYER_USE_DECODEBIN(player)) {
6548 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6549 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6550 "uri", profile.uri, NULL);
6553 SECURE_LOGD("next playback uri: %s", uri);
6558 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6560 #define REPEAT_COUNT_INFINITE -1
6561 #define REPEAT_COUNT_MIN 2
6562 #define ORIGINAL_URI_ONLY 1
6564 MMHandleType attrs = 0;
6568 guint num_of_uri = 0;
6569 int profile_tv = -1;
6573 LOGD("checking for gapless play option");
6575 if (player->build_audio_offload) {
6576 LOGE("offload path is not supportable.");
6580 if (player->pipeline->textbin) {
6581 LOGE("subtitle path is enabled. gapless play is not supported.");
6585 attrs = MMPLAYER_GET_ATTRS(player);
6587 LOGE("fail to get attributes.");
6591 mm_attrs_multiple_get(player->attrs, NULL,
6592 "content_video_found", &video,
6593 "profile_play_count", &count,
6594 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6596 /* gapless playback is not supported in case of video at TV profile. */
6597 profile_tv = __mmplayer_check_profile();
6598 if (profile_tv && video) {
6599 LOGW("not support video gapless playback");
6603 /* check repeat count in case of audio */
6605 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6606 LOGW("gapless is disabled");
6610 num_of_uri = g_list_length(player->uri_info.uri_list);
6611 if (!MMPLAYER_USE_DECODEBIN(player))
6612 player->gapless.running = TRUE;
6614 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6616 if (num_of_uri == ORIGINAL_URI_ONLY) {
6617 /* audio looping path */
6618 if (count >= REPEAT_COUNT_MIN) {
6619 /* decrease play count */
6620 /* we succeeded to rewind. update play count and then wait for next EOS */
6622 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6623 } else if (count != REPEAT_COUNT_INFINITE) {
6624 LOGD("there is no next uri and no repeat");
6628 if (!MMPLAYER_USE_DECODEBIN(player)) {
6629 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6630 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6631 "uri", player->profile.uri, NULL);
6634 LOGD("looping cnt %d", count);
6636 /* gapless playback path */
6637 if (!__mmplayer_get_next_uri(player)) {
6638 LOGE("failed to get next uri");
6645 LOGE("unable to play gapless path. EOS will be posted soon");
6650 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6652 GstPad *sinkpad = g_value_get_object (item);
6653 GstElement *element = GST_ELEMENT(user_data);
6654 if (!sinkpad || !element) {
6655 LOGE("invalid parameter");
6659 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6660 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6664 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6666 mmplayer_gst_element_t *sinkbin = NULL;
6667 main_element_id_e concatId = MMPLAYER_M_NUM;
6668 main_element_id_e sinkId = MMPLAYER_M_NUM;
6669 gboolean send_notice = FALSE;
6670 GstElement *element;
6674 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6676 LOGD("type %d", type);
6679 case MM_PLAYER_TRACK_TYPE_AUDIO:
6680 concatId = MMPLAYER_M_A_CONCAT;
6681 sinkId = MMPLAYER_A_BIN;
6682 sinkbin = player->pipeline->audiobin;
6684 case MM_PLAYER_TRACK_TYPE_VIDEO:
6685 concatId = MMPLAYER_M_V_CONCAT;
6686 sinkId = MMPLAYER_V_BIN;
6687 sinkbin = player->pipeline->videobin;
6690 case MM_PLAYER_TRACK_TYPE_TEXT:
6691 concatId = MMPLAYER_M_T_CONCAT;
6692 sinkId = MMPLAYER_T_BIN;
6693 sinkbin = player->pipeline->textbin;
6696 LOGE("requested type is not supportable");
6701 element = player->pipeline->mainbin[concatId].gst;
6705 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6706 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6707 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6708 if (srcpad && sinkpad) {
6709 /* after getting drained signal there is no data flows, so no need to do pad_block */
6710 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6711 gst_pad_unlink(srcpad, sinkpad);
6713 /* send custom event to sink pad to handle it at video sink */
6715 LOGD("send custom event to sinkpad");
6716 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6717 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6718 gst_pad_send_event(sinkpad, event);
6721 gst_object_unref(srcpad);
6722 gst_object_unref(sinkpad);
6725 LOGD("release concat request pad");
6726 /* release and unref requests pad from the selector */
6727 iter = gst_element_iterate_sink_pads(element);
6728 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6729 gst_iterator_resync(iter);
6730 gst_iterator_free(iter);
6736 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6738 mmplayer_track_t *selector = &player->track[type];
6739 mmplayer_gst_element_t *sinkbin = NULL;
6740 main_element_id_e selectorId = MMPLAYER_M_NUM;
6741 main_element_id_e sinkId = MMPLAYER_M_NUM;
6742 GstPad *srcpad = NULL;
6743 GstPad *sinkpad = NULL;
6744 gboolean send_notice = FALSE;
6747 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6749 LOGD("type %d", type);
6752 case MM_PLAYER_TRACK_TYPE_AUDIO:
6753 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6754 sinkId = MMPLAYER_A_BIN;
6755 sinkbin = player->pipeline->audiobin;
6757 case MM_PLAYER_TRACK_TYPE_VIDEO:
6758 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6759 sinkId = MMPLAYER_V_BIN;
6760 sinkbin = player->pipeline->videobin;
6763 case MM_PLAYER_TRACK_TYPE_TEXT:
6764 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6765 sinkId = MMPLAYER_T_BIN;
6766 sinkbin = player->pipeline->textbin;
6769 LOGE("requested type is not supportable");
6774 if (player->pipeline->mainbin[selectorId].gst) {
6777 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6779 if (selector->event_probe_id != 0)
6780 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6781 selector->event_probe_id = 0;
6783 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6784 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6786 if (srcpad && sinkpad) {
6787 /* after getting drained signal there is no data flows, so no need to do pad_block */
6788 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6789 gst_pad_unlink(srcpad, sinkpad);
6791 /* send custom event to sink pad to handle it at video sink */
6793 LOGD("send custom event to sinkpad");
6794 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6795 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6796 gst_pad_send_event(sinkpad, event);
6800 gst_object_unref(sinkpad);
6803 gst_object_unref(srcpad);
6806 LOGD("selector release");
6808 /* release and unref requests pad from the selector */
6809 for (n = 0; n < selector->streams->len; n++) {
6810 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6811 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6814 g_ptr_array_set_size(selector->streams, 0);
6816 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6817 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6818 player->pipeline->mainbin[selectorId].gst)) {
6819 LOGE("failed to remove selector");
6820 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6823 player->pipeline->mainbin[selectorId].gst = NULL;
6831 __mmplayer_deactivate_old_path(mmplayer_t *player)
6834 MMPLAYER_RETURN_IF_FAIL(player);
6836 if (MMPLAYER_USE_DECODEBIN(player)) {
6837 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6838 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6839 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6840 LOGE("deactivate selector error");
6844 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6845 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6846 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6847 LOGE("deactivate concat error");
6852 _mmplayer_track_destroy(player);
6853 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6855 if (player->streamer) {
6856 _mm_player_streaming_initialize(player->streamer, FALSE);
6857 _mm_player_streaming_destroy(player->streamer);
6858 player->streamer = NULL;
6861 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6867 if (!player->msg_posted) {
6868 MMMessageParamType msg = {0,};
6871 msg.code = MM_ERROR_PLAYER_INTERNAL;
6872 LOGE("gapless_uri_play> deactivate error");
6874 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6875 player->msg_posted = TRUE;
6881 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6883 int result = MM_ERROR_NONE;
6884 mmplayer_t *player = (mmplayer_t *)hplayer;
6887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6888 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6890 if (mm_player_set_attribute(hplayer, NULL,
6891 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6892 LOGE("failed to set attribute");
6893 result = MM_ERROR_PLAYER_INTERNAL;
6895 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6896 LOGE("failed to add the original uri in the uri list.");
6904 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6906 mmplayer_t *player = (mmplayer_t *)hplayer;
6907 guint num_of_list = 0;
6911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6912 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6914 if (player->pipeline && player->pipeline->textbin) {
6915 LOGE("subtitle path is enabled.");
6916 return MM_ERROR_PLAYER_INVALID_STATE;
6919 num_of_list = g_list_length(player->uri_info.uri_list);
6921 if (is_first_path) {
6922 if (num_of_list == 0) {
6923 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6924 SECURE_LOGD("add original path : %s", uri);
6926 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6927 player->uri_info.uri_list = g_list_prepend(
6928 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6929 SECURE_LOGD("change original path : %s", uri);
6932 MMHandleType attrs = 0;
6933 attrs = MMPLAYER_GET_ATTRS(player);
6935 if (num_of_list == 0) {
6936 char *original_uri = NULL;
6939 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6941 if (!original_uri) {
6942 LOGE("there is no original uri.");
6943 return MM_ERROR_PLAYER_INVALID_STATE;
6946 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6947 player->uri_info.uri_idx = 0;
6949 SECURE_LOGD("add original path at first : %s", original_uri);
6953 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6954 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6958 return MM_ERROR_NONE;
6962 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6964 mmplayer_t *player = (mmplayer_t *)hplayer;
6965 char *next_uri = NULL;
6966 guint num_of_list = 0;
6969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6971 num_of_list = g_list_length(player->uri_info.uri_list);
6973 if (num_of_list > 0) {
6974 gint uri_idx = player->uri_info.uri_idx;
6976 if (uri_idx < num_of_list - 1)
6981 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6982 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6984 *uri = g_strdup(next_uri);
6988 return MM_ERROR_NONE;
6992 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6993 GstCaps *caps, gpointer data)
6995 mmplayer_t *player = (mmplayer_t *)data;
6996 const gchar *klass = NULL;
6997 const gchar *mime = NULL;
6998 gchar *caps_str = NULL;
7000 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7001 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7002 caps_str = gst_caps_to_string(caps);
7004 LOGW("unknown type of caps : %s from %s",
7005 caps_str, GST_ELEMENT_NAME(elem));
7007 MMPLAYER_FREEIF(caps_str);
7009 /* There is no available codec. */
7010 _mmplayer_update_not_supported_codec_info(player, klass, mime);
7014 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
7015 GstCaps *caps, gpointer data)
7017 mmplayer_t *player = (mmplayer_t *)data;
7018 const char *mime = NULL;
7019 gboolean ret = TRUE;
7021 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7022 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7024 if (g_str_has_prefix(mime, "audio")) {
7025 GstStructure *caps_structure = NULL;
7026 gint samplerate = 0;
7028 gchar *caps_str = NULL;
7030 caps_structure = gst_caps_get_structure(caps, 0);
7031 gst_structure_get_int(caps_structure, "rate", &samplerate);
7032 gst_structure_get_int(caps_structure, "channels", &channels);
7034 if ((channels > 0 && samplerate == 0)) {
7035 LOGD("exclude audio...");
7039 caps_str = gst_caps_to_string(caps);
7040 /* set it directly because not sent by TAG */
7041 if (g_strrstr(caps_str, "mobile-xmf"))
7042 mm_player_set_attribute((MMHandleType)player, NULL,
7043 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7045 MMPLAYER_FREEIF(caps_str);
7046 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7047 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7048 LOGD("video is already linked, allow the stream switch");
7051 LOGD("video is already linked");
7055 LOGD("found new stream");
7062 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7064 gboolean ret = FALSE;
7065 GDBusConnection *conn = NULL;
7067 GVariant *result = NULL;
7068 const gchar *dbus_device_type = NULL;
7069 const gchar *dbus_ret = NULL;
7072 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7074 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7079 result = g_dbus_connection_call_sync(conn,
7080 "org.pulseaudio.Server",
7081 "/org/pulseaudio/StreamManager",
7082 "org.pulseaudio.StreamManager",
7083 "GetCurrentMediaRoutingPath",
7084 g_variant_new("(s)", "out"),
7085 G_VARIANT_TYPE("(ss)"),
7086 G_DBUS_CALL_FLAGS_NONE,
7090 if (!result || err) {
7091 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7096 /* device type is listed in stream-map.json at mmfw-sysconf */
7097 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7099 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7100 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7103 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7104 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7105 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7106 LOGD("audio offload is supportable");
7112 LOGD("audio offload is not supportable");
7115 g_variant_unref(result);
7117 g_object_unref(conn);
7122 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7124 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7125 gint64 position = 0;
7127 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7128 player->pipeline && player->pipeline->mainbin);
7130 MMPLAYER_CMD_LOCK(player);
7131 current_state = MMPLAYER_CURRENT_STATE(player);
7133 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7134 LOGW("getting current position failed in paused");
7136 _mmplayer_unrealize((MMHandleType)player);
7137 _mmplayer_realize((MMHandleType)player);
7139 _mmplayer_set_position((MMHandleType)player, position);
7141 /* async not to be blocked in streaming case */
7142 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7144 _mmplayer_pause((MMHandleType)player);
7146 if (current_state == MM_PLAYER_STATE_PLAYING)
7147 _mmplayer_start((MMHandleType)player);
7148 MMPLAYER_CMD_UNLOCK(player);
7150 LOGD("rebuilding audio pipeline is completed.");
7153 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7155 mmplayer_t *player = (mmplayer_t *)user_data;
7156 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7157 gboolean is_supportable = FALSE;
7159 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7160 LOGW("failed to get device type");
7162 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7164 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7165 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7166 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7167 LOGD("ignore this dev connected info");
7171 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7172 if (player->build_audio_offload == is_supportable) {
7173 LOGD("keep current pipeline without re-building");
7177 /* rebuild pipeline */
7178 LOGD("re-build pipeline - offload: %d", is_supportable);
7179 player->build_audio_offload = FALSE;
7180 __mmplayer_rebuild_audio_pipeline(player);
7186 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7188 unsigned int id = 0;
7190 if (player->audio_device_cb_id != 0) {
7191 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7195 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7196 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7197 LOGD("added device connected cb (%u)", id);
7198 player->audio_device_cb_id = id;
7200 LOGW("failed to add device connected cb");
7207 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7209 mmplayer_t *player = (mmplayer_t *)hplayer;
7212 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7213 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7215 *activated = player->build_audio_offload;
7217 LOGD("offload activated : %d", (int)*activated);
7220 return MM_ERROR_NONE;
7224 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7227 this function need to be updated according to the supported media format
7228 @see player->ini.audio_offload_media_format */
7230 if (__mmplayer_is_only_mp3_type(player->type_caps_str)) {
7231 LOGD("offload supportable media format type");
7239 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7241 gboolean ret = FALSE;
7242 GstElementFactory *factory = NULL;
7245 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7247 LOGD("current stream : %s, sink: %s", player->type_caps_str, player->ini.audio_offload_sink_element);
7248 if (!__mmplayer_is_offload_supported_type(player))
7251 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7252 LOGD("there is no audio offload sink");
7256 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7257 LOGW("there is no audio device type to support offload");
7261 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7263 LOGW("there is no installed audio offload sink element");
7266 gst_object_unref(factory);
7268 if (_mmplayer_acquire_hw_resource(player,
7269 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7270 LOGE("failed to acquire audio offload decoder resource");
7274 if (!__mmplayer_add_audio_device_connected_cb(player))
7277 if (!__mmplayer_is_audio_offload_device_type(player))
7280 LOGD("audio offload can be built");
7285 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7291 static GstAutoplugSelectResult
7292 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7294 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7295 int audio_offload = 0;
7297 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7298 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7300 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7301 LOGD("expose audio path to build offload output path");
7302 player->build_audio_offload = TRUE;
7303 /* update codec info */
7304 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7305 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7306 player->audiodec_linked = 1;
7308 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7312 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7313 And need to consider the multi-track audio content.
7314 There is no HW audio decoder in public. */
7316 /* set stream information */
7317 if (!player->audiodec_linked)
7318 _mmplayer_set_audio_attrs(player, caps);
7320 /* update codec info */
7321 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7322 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7323 player->audiodec_linked = 1;
7325 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7327 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7328 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7330 /* mark video decoder for acquire */
7331 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7332 LOGW("video decoder resource is already acquired, skip it.");
7333 ret = GST_AUTOPLUG_SELECT_SKIP;
7337 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7338 LOGE("failed to acquire video decoder resource");
7339 ret = GST_AUTOPLUG_SELECT_SKIP;
7342 player->interrupted_by_resource = FALSE;
7345 /* update codec info */
7346 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7347 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7348 player->videodec_linked = 1;
7356 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7357 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7359 #define DEFAULT_IDX 0xFFFF
7360 #define MIN_FACTORY_NUM 2
7361 mmplayer_t *player = (mmplayer_t *)data;
7362 GValueArray *new_factories = NULL;
7363 GValue val = { 0, };
7364 GstElementFactory *factory = NULL;
7365 const gchar *klass = NULL;
7366 gchar *factory_name = NULL;
7367 guint hw_dec_idx = DEFAULT_IDX;
7368 guint first_sw_dec_idx = DEFAULT_IDX;
7369 guint last_sw_dec_idx = DEFAULT_IDX;
7370 guint new_pos = DEFAULT_IDX;
7371 guint rm_pos = DEFAULT_IDX;
7372 int audio_codec_type;
7373 int video_codec_type;
7374 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7376 if (factories->n_values < MIN_FACTORY_NUM)
7379 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7380 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7383 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7385 for (int i = 0 ; i < factories->n_values ; i++) {
7386 gchar *hw_dec_info = NULL;
7387 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7389 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7391 LOGW("failed to get factory object");
7394 klass = gst_element_factory_get_klass(factory);
7395 factory_name = GST_OBJECT_NAME(factory);
7398 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7400 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7401 if (!player->need_audio_dec_sorting) {
7402 LOGD("sorting is not required");
7405 codec_type = audio_codec_type;
7406 hw_dec_info = player->ini.audiocodec_element_hw;
7407 sw_dec_info = player->ini.audiocodec_element_sw;
7408 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7409 if (!player->need_video_dec_sorting) {
7410 LOGD("sorting is not required");
7413 codec_type = video_codec_type;
7414 hw_dec_info = player->ini.videocodec_element_hw;
7415 sw_dec_info = player->ini.videocodec_element_sw;
7420 if (g_strrstr(factory_name, hw_dec_info)) {
7423 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7424 if (strstr(factory_name, sw_dec_info[j])) {
7425 last_sw_dec_idx = i;
7426 if (first_sw_dec_idx == DEFAULT_IDX) {
7427 first_sw_dec_idx = i;
7432 if (first_sw_dec_idx == DEFAULT_IDX)
7433 LOGW("unknown codec %s", factory_name);
7437 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7440 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7441 if (hw_dec_idx < first_sw_dec_idx)
7443 new_pos = first_sw_dec_idx;
7444 rm_pos = hw_dec_idx + 1;
7445 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7446 if (last_sw_dec_idx < hw_dec_idx)
7448 new_pos = last_sw_dec_idx + 1;
7449 rm_pos = hw_dec_idx;
7454 /* change position - insert H/W decoder according to the new position */
7455 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7457 LOGW("failed to get factory object");
7460 new_factories = g_value_array_copy(factories);
7461 g_value_init (&val, G_TYPE_OBJECT);
7462 g_value_set_object (&val, factory);
7463 g_value_array_insert(new_factories, new_pos, &val);
7464 g_value_unset (&val);
7465 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7467 for (int i = 0 ; i < new_factories->n_values ; i++) {
7468 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7470 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7471 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7473 LOGE("[Re-arranged] failed to get factory object");
7476 return new_factories;
7480 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7481 GstCaps *caps, GstElementFactory *factory, gpointer data)
7483 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7484 mmplayer_t *player = (mmplayer_t *)data;
7486 gchar *factory_name = NULL;
7487 gchar *caps_str = NULL;
7488 const gchar *klass = NULL;
7491 factory_name = GST_OBJECT_NAME(factory);
7492 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7493 caps_str = gst_caps_to_string(caps);
7495 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7497 /* store type string */
7498 if (player->type_caps_str == NULL) {
7499 player->type_caps_str = gst_caps_to_string(caps);
7500 __mmplayer_update_content_type_info(player);
7503 /* filtering exclude keyword */
7504 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7505 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7506 LOGW("skipping [%s] by exclude keyword [%s]",
7507 factory_name, player->ini.exclude_element_keyword[idx]);
7509 result = GST_AUTOPLUG_SELECT_SKIP;
7514 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7515 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7516 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7517 factory_name, player->ini.unsupported_codec_keyword[idx]);
7518 result = GST_AUTOPLUG_SELECT_SKIP;
7523 /* exclude webm format */
7524 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7525 * because webm format is not supportable.
7526 * If webm is disabled in "autoplug-continue", there is no state change
7527 * failure or error because the decodebin will expose the pad directly.
7528 * It make MSL invoke _prepare_async_callback.
7529 * So, we need to disable webm format in "autoplug-select" */
7530 if (caps_str && strstr(caps_str, "webm")) {
7531 LOGW("webm is not supported");
7532 result = GST_AUTOPLUG_SELECT_SKIP;
7536 /* check factory class for filtering */
7537 /* NOTE : msl don't need to use image plugins.
7538 * So, those plugins should be skipped for error handling.
7540 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7541 LOGD("skipping [%s] by not required", factory_name);
7542 result = GST_AUTOPLUG_SELECT_SKIP;
7546 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7547 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7548 // TO CHECK : subtitle if needed, add subparse exception.
7549 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7550 result = GST_AUTOPLUG_SELECT_SKIP;
7554 if (g_strrstr(factory_name, "mpegpsdemux")) {
7555 LOGD("skipping PS container - not support");
7556 result = GST_AUTOPLUG_SELECT_SKIP;
7560 if (g_strrstr(factory_name, "mssdemux"))
7561 player->smooth_streaming = TRUE;
7563 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7564 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7567 GstStructure *str = NULL;
7569 /* parsebin in adaptivedemux get error if there is no parser */
7570 if ((!g_strrstr(GST_ELEMENT_NAME(bin), "parsebin")) ||
7571 ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player)))) {
7572 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7574 /* don't make video because of not required */
7575 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7576 (!player->set_mode.video_export)) {
7577 LOGD("no need video decoding, expose pad");
7578 result = GST_AUTOPLUG_SELECT_EXPOSE;
7583 /* get w/h for omx state-tune */
7584 /* FIXME: deprecated? */
7585 str = gst_caps_get_structure(caps, 0);
7586 gst_structure_get_int(str, "width", &width);
7589 if (player->v_stream_caps) {
7590 gst_caps_unref(player->v_stream_caps);
7591 player->v_stream_caps = NULL;
7594 player->v_stream_caps = gst_caps_copy(caps);
7595 LOGD("take caps for video state tune");
7596 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7600 if (g_strrstr(klass, "Codec/Decoder")) {
7601 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7602 if (result != GST_AUTOPLUG_SELECT_TRY) {
7603 LOGW("skip add decoder");
7609 MMPLAYER_FREEIF(caps_str);
7615 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7618 int ret = MM_ERROR_NONE;
7619 mmplayer_t *player = (mmplayer_t *)data;
7620 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7621 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7622 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7625 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7627 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7629 if (MMPLAYER_USE_DECODEBIN(player))
7632 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7635 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7637 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7639 LOGD("remove videobin");
7640 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7641 GST_STATE_NULL, FALSE, timeout);
7642 if (ret != MM_ERROR_NONE) {
7643 LOGE("fail to change state of videobin to NULL");
7647 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7648 LOGE("failed to remove videobin");
7649 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7652 LOGD("remove concat");
7653 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7654 GST_STATE_NULL, FALSE, timeout);
7655 if (ret != MM_ERROR_NONE) {
7656 LOGE("fail to change state of concat to NULL");
7660 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7661 LOGE("failed to remove video concat");
7662 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7665 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7666 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7667 MMPLAYER_FREEIF(player->pipeline->videobin);
7669 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7670 if (ret != MM_ERROR_NONE)
7671 LOGE("failed to release overlay resources");
7673 player->videodec_linked = 0;
7675 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7680 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7682 mmplayer_t *player = (mmplayer_t *)data;
7685 MMPLAYER_RETURN_IF_FAIL(player);
7687 LOGD("got about to finish signal");
7689 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7690 LOGW("Fail to get cmd lock");
7694 if (!__mmplayer_verify_gapless_play_path(player)) {
7695 LOGD("decoding is finished.");
7696 if (MMPLAYER_USE_DECODEBIN(player)) {
7697 MMPLAYER_CMD_UNLOCK(player);
7702 if (MMPLAYER_USE_DECODEBIN(player)) {
7703 _mmplayer_set_reconfigure_state(player, TRUE);
7704 MMPLAYER_CMD_UNLOCK(player);
7705 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7706 __mmplayer_deactivate_old_path(player);
7708 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7709 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7710 MMPLAYER_CMD_UNLOCK(player);
7717 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7719 mmplayer_t *player = (mmplayer_t *)data;
7720 GstIterator *iter = NULL;
7721 GValue item = { 0, };
7723 gboolean done = FALSE;
7724 gboolean is_all_drained = TRUE;
7727 MMPLAYER_RETURN_IF_FAIL(player);
7729 LOGD("got drained signal");
7731 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7732 LOGW("Fail to get cmd lock");
7736 if (!__mmplayer_verify_gapless_play_path(player)) {
7737 LOGD("decoding is finished.");
7738 MMPLAYER_CMD_UNLOCK(player);
7742 _mmplayer_set_reconfigure_state(player, TRUE);
7743 MMPLAYER_CMD_UNLOCK(player);
7745 /* check decodebin src pads whether they received EOS or not */
7746 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7749 switch (gst_iterator_next(iter, &item)) {
7750 case GST_ITERATOR_OK:
7751 pad = g_value_get_object(&item);
7752 if (pad && !GST_PAD_IS_EOS(pad)) {
7753 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7754 is_all_drained = FALSE;
7757 g_value_reset(&item);
7759 case GST_ITERATOR_RESYNC:
7760 gst_iterator_resync(iter);
7762 case GST_ITERATOR_ERROR:
7763 case GST_ITERATOR_DONE:
7768 g_value_unset(&item);
7769 gst_iterator_free(iter);
7771 if (!is_all_drained) {
7772 LOGD("Wait util the all pads get EOS.");
7777 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7778 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7780 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7781 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7782 __mmplayer_deactivate_old_path(player);
7788 _mmplayer_gst_element_added(GstBin *bin, GstElement *element, gpointer data)
7790 mmplayer_t *player = (mmplayer_t *)data;
7791 const gchar *klass = NULL;
7792 gchar *factory_name = NULL;
7794 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7795 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7797 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7799 if (__mmplayer_add_dump_buffer_probe(player, element))
7800 LOGD("add buffer probe");
7802 if (g_strrstr(klass, "Decoder")) {
7803 if (g_strrstr(klass, "Audio")) {
7804 player->audio_decoders = g_list_append(player->audio_decoders,
7805 g_strdup(GST_ELEMENT_NAME(element)));
7807 /* update codec info */
7808 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7809 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7810 player->audiodec_linked = 1;
7811 } else if (g_strrstr(klass, "Video")) {
7812 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7813 /* update codec info */
7814 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7815 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7816 player->videodec_linked = 1;
7819 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7821 GstCaps *caps = NULL;
7822 GstStructure *str = NULL;
7823 const gchar *name = NULL;
7824 gboolean caps_ret = TRUE;
7826 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7827 if (caps_ret && str) {
7828 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7829 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7830 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7831 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7832 LOGD("Send SPS and PPS Insertion every IDR frame");
7836 gst_object_unref(GST_OBJECT(srcpad));
7840 } else if (g_strrstr(klass, "Demuxer")) {
7841 if (g_strrstr(klass, "Adaptive")) {
7842 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7843 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7845 MMPLAYER_FREEIF(player->type_caps_str);
7847 if (g_strrstr(factory_name, "hlsdemux")) {
7848 player->type_caps_str = g_strdup("application/x-hls");
7849 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7850 } else if (g_strrstr(factory_name, "dashdemux")) {
7851 player->type_caps_str = g_strdup("application/dash+xml");
7852 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7854 LOGE("not supported type");
7857 player->streamer->is_adaptive_streaming = TRUE;
7859 if (player->streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
7860 player->streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
7862 LOGD("max variant limit: %d, %d, %d, prebuffer time: %d ms",
7863 player->adaptive_info.limit.bandwidth,
7864 player->adaptive_info.limit.width,
7865 player->adaptive_info.limit.height,
7866 player->streamer->buffering_req.prebuffer_time);
7868 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7869 "max-bitrate", player->adaptive_info.limit.bandwidth,
7870 "max-video-width", player->adaptive_info.limit.width,
7871 "max-video-height", player->adaptive_info.limit.height,
7872 "low-watermark-time", (guint64)(player->streamer->buffering_req.prebuffer_time * GST_MSECOND),
7876 LOGD("plugged element is demuxer. take it");
7878 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7879 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7881 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7882 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7883 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7886 if (g_strrstr(factory_name, "mpegaudioparse")) {
7887 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7888 (__mmplayer_is_only_mp3_type(player->type_caps_str))) {
7889 LOGD("[mpegaudioparse] set streaming pull mode.");
7890 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7892 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7893 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7894 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7896 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7897 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7899 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7900 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7901 _mm_player_streaming_set_multiqueue(player->streamer, element);
7902 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7910 __mmplayer_release_misc(mmplayer_t *player)
7913 bool cur_mode = player->set_mode.rich_audio;
7916 MMPLAYER_RETURN_IF_FAIL(player);
7918 player->sent_bos = FALSE;
7919 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7921 player->seek_state = MMPLAYER_SEEK_NONE;
7923 player->total_bitrate = 0;
7924 player->total_maximum_bitrate = 0;
7926 player->not_found_demuxer = 0;
7928 player->last_position = 0;
7929 player->duration = 0;
7930 player->http_content_size = 0;
7931 player->not_supported_codec = MISSING_PLUGIN_NONE;
7932 player->can_support_codec = FOUND_PLUGIN_NONE;
7933 player->pending_seek.is_pending = false;
7934 player->pending_seek.pos = 0;
7935 player->msg_posted = FALSE;
7936 player->has_many_types = FALSE;
7937 player->is_subtitle_force_drop = FALSE;
7938 player->play_subtitle = FALSE;
7939 player->adjust_subtitle_pos = 0;
7940 player->has_closed_caption = FALSE;
7941 player->set_mode.video_export = false;
7942 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7943 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7945 player->set_mode.rich_audio = cur_mode;
7947 if (player->audio_device_cb_id > 0 &&
7948 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7949 LOGW("failed to remove audio device_connected_callback");
7950 player->audio_device_cb_id = 0;
7952 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7953 player->bitrate[i] = 0;
7954 player->maximum_bitrate[i] = 0;
7957 /* free memory related to audio effect */
7958 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7960 if (player->adaptive_info.var_list) {
7961 g_list_free_full(player->adaptive_info.var_list, g_free);
7962 player->adaptive_info.var_list = NULL;
7965 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7966 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7967 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7969 /* Reset video360 settings to their defaults in case if the pipeline is to be
7972 player->video360_metadata.is_spherical = -1;
7973 player->is_openal_plugin_used = FALSE;
7975 player->is_content_spherical = FALSE;
7976 player->is_video360_enabled = TRUE;
7977 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7978 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7979 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7980 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7981 player->video360_zoom = 1.0f;
7982 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7983 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7985 player->sound.rg_enable = false;
7987 __mmplayer_initialize_video_roi(player);
7992 __mmplayer_release_misc_post(mmplayer_t *player)
7994 gchar *original_uri = NULL;
7997 /* player->pipeline is already released before. */
7998 MMPLAYER_RETURN_IF_FAIL(player);
8000 player->video_decoded_cb = NULL;
8001 player->video_decoded_cb_user_param = NULL;
8002 player->video_stream_prerolled = false;
8004 player->audio_decoded_cb = NULL;
8005 player->audio_decoded_cb_user_param = NULL;
8006 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
8008 player->audio_stream_changed_cb = NULL;
8009 player->audio_stream_changed_cb_user_param = NULL;
8011 mm_player_set_attribute((MMHandleType)player, NULL,
8012 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
8014 /* clean found audio decoders */
8015 if (player->audio_decoders) {
8016 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
8017 player->audio_decoders = NULL;
8020 /* clean the uri list except original uri */
8021 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
8023 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8024 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
8025 g_list_free_full(tmp, (GDestroyNotify)g_free);
8028 LOGW("failed to get original uri info");
8030 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
8031 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
8032 MMPLAYER_FREEIF(original_uri);
8035 /* clear the audio stream buffer list */
8036 _mmplayer_audio_stream_clear_buffer(player, FALSE);
8038 /* clear the video stream bo list */
8039 __mmplayer_video_stream_destroy_bo_list(player);
8040 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8042 if (player->profile.input_mem.buf) {
8043 free(player->profile.input_mem.buf);
8044 player->profile.input_mem.buf = NULL;
8046 player->profile.input_mem.len = 0;
8047 player->profile.input_mem.offset = 0;
8049 player->uri_info.uri_idx = 0;
8054 __mmplayer_check_subtitle(mmplayer_t *player)
8056 MMHandleType attrs = 0;
8057 char *subtitle_uri = NULL;
8061 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8063 /* get subtitle attribute */
8064 attrs = MMPLAYER_GET_ATTRS(player);
8068 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8069 if (!subtitle_uri || !strlen(subtitle_uri))
8072 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8073 player->is_external_subtitle_present = TRUE;
8081 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8083 MMPLAYER_RETURN_IF_FAIL(player);
8085 if (player->eos_timer) {
8086 LOGD("cancel eos timer");
8087 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8088 player->eos_timer = 0;
8095 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8099 MMPLAYER_RETURN_IF_FAIL(player);
8100 MMPLAYER_RETURN_IF_FAIL(sink);
8103 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8105 player->sink_elements = g_list_append(player->sink_elements, sink);
8111 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8115 MMPLAYER_RETURN_IF_FAIL(player);
8116 MMPLAYER_RETURN_IF_FAIL(sink);
8118 player->sink_elements = g_list_remove(player->sink_elements, sink);
8124 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8125 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8127 mmplayer_signal_item_t *item = NULL;
8130 MMPLAYER_RETURN_IF_FAIL(player);
8132 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8133 LOGE("invalid signal type [%d]", type);
8137 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8139 LOGE("cannot connect signal [%s]", signal);
8144 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8145 player->signals[type] = g_list_append(player->signals[type], item);
8151 /* NOTE : be careful with calling this api. please refer to below glib comment
8152 * glib comment : Note that there is a bug in GObject that makes this function much
8153 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8154 * will no longer be called, but, the signal handler is not currently disconnected.
8155 * If the instance is itself being freed at the same time than this doesn't matter,
8156 * since the signal will automatically be removed, but if instance persists,
8157 * then the signal handler will leak. You should not remove the signal yourself
8158 * because in a future versions of GObject, the handler will automatically be
8161 * It's possible to work around this problem in a way that will continue to work
8162 * with future versions of GObject by checking that the signal handler is still
8163 * connected before disconnected it:
8165 * if (g_signal_handler_is_connected(instance, id))
8166 * g_signal_handler_disconnect(instance, id);
8169 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8171 GList *sig_list = NULL;
8172 mmplayer_signal_item_t *item = NULL;
8176 MMPLAYER_RETURN_IF_FAIL(player);
8178 LOGD("release signals type : %d", type);
8180 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8181 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8182 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8183 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8184 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8185 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8189 sig_list = player->signals[type];
8191 for (; sig_list; sig_list = sig_list->next) {
8192 item = sig_list->data;
8194 if (item && item->obj) {
8195 if (g_signal_handler_is_connected(item->obj, item->sig))
8196 g_signal_handler_disconnect(item->obj, item->sig);
8199 MMPLAYER_FREEIF(item);
8202 g_list_free(player->signals[type]);
8203 player->signals[type] = NULL;
8211 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8213 mmplayer_t *player = 0;
8214 int prev_display_surface_type = 0;
8218 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8220 player = MM_PLAYER_CAST(handle);
8222 /* check video sinkbin is created */
8223 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8224 LOGW("Videosink is already created");
8225 return MM_ERROR_NONE;
8228 LOGD("videosink element is not yet ready");
8230 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8231 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8233 return MM_ERROR_INVALID_ARGUMENT;
8236 /* load previous attributes */
8237 if (player->attrs) {
8238 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8239 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8240 if (prev_display_surface_type == surface_type) {
8241 LOGD("incoming display surface type is same as previous one, do nothing..");
8243 return MM_ERROR_NONE;
8246 LOGE("failed to load attributes");
8248 return MM_ERROR_PLAYER_INTERNAL;
8251 /* videobin is not created yet, so we just set attributes related to display surface */
8252 LOGD("store display attribute for given surface type(%d)", surface_type);
8253 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8254 "display_overlay", wl_surface_id, NULL);
8257 return MM_ERROR_NONE;
8260 /* Note : if silent is true, then subtitle would not be displayed. :*/
8262 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8264 mmplayer_t *player = (mmplayer_t *)hplayer;
8268 /* check player handle */
8269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8271 player->set_mode.subtitle_off = silent;
8273 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8277 return MM_ERROR_NONE;
8281 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8283 mmplayer_gst_element_t *mainbin = NULL;
8284 mmplayer_gst_element_t *textbin = NULL;
8285 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8286 GstState current_state = GST_STATE_VOID_PENDING;
8287 GstState element_state = GST_STATE_VOID_PENDING;
8288 GstState element_pending_state = GST_STATE_VOID_PENDING;
8290 GstEvent *event = NULL;
8291 int result = MM_ERROR_NONE;
8293 GstClock *curr_clock = NULL;
8294 GstClockTime base_time, start_time, curr_time;
8299 /* check player handle */
8300 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8302 player->pipeline->mainbin &&
8303 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8305 mainbin = player->pipeline->mainbin;
8306 textbin = player->pipeline->textbin;
8308 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8310 // sync clock with current pipeline
8311 curr_clock = gst_element_get_clock(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8312 curr_time = gst_clock_get_time(curr_clock);
8314 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8315 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8317 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8318 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8320 if (current_state > GST_STATE_READY) {
8321 // sync state with current pipeline
8322 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8323 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8324 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8326 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8327 if (GST_STATE_CHANGE_FAILURE == ret) {
8328 LOGE("fail to state change.");
8329 result = MM_ERROR_PLAYER_INTERNAL;
8331 gst_object_unref(curr_clock);
8335 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8336 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8339 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8340 gst_object_unref(curr_clock);
8343 // seek to current position
8344 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8345 result = MM_ERROR_PLAYER_INVALID_STATE;
8346 LOGE("gst_element_query_position failed, invalid state");
8350 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8351 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);
8353 _mmplayer_gst_send_event_to_sink(player, event);
8355 result = MM_ERROR_PLAYER_INTERNAL;
8356 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8360 /* sync state with current pipeline */
8361 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8362 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8363 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8365 return MM_ERROR_NONE;
8368 /* release text pipeline resource */
8369 player->textsink_linked = 0;
8371 /* release signal */
8372 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8374 /* release textbin with it's children */
8375 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8376 MMPLAYER_FREEIF(player->pipeline->textbin);
8377 player->pipeline->textbin = NULL;
8379 /* release subtitle elem */
8380 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8381 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8387 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8389 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8390 GstState current_state = GST_STATE_VOID_PENDING;
8392 MMHandleType attrs = 0;
8393 mmplayer_gst_element_t *mainbin = NULL;
8394 mmplayer_gst_element_t *textbin = NULL;
8396 gchar *subtitle_uri = NULL;
8397 int result = MM_ERROR_NONE;
8398 const gchar *charset = NULL;
8402 /* check player handle */
8403 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8405 player->pipeline->mainbin &&
8406 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8407 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8409 mainbin = player->pipeline->mainbin;
8410 textbin = player->pipeline->textbin;
8412 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8413 if (current_state < GST_STATE_READY) {
8414 result = MM_ERROR_PLAYER_INVALID_STATE;
8415 LOGE("Pipeline is not in proper state");
8419 attrs = MMPLAYER_GET_ATTRS(player);
8421 LOGE("cannot get content attribute");
8422 result = MM_ERROR_PLAYER_INTERNAL;
8426 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8427 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8428 LOGE("subtitle uri is not proper filepath");
8429 result = MM_ERROR_PLAYER_INVALID_URI;
8433 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8434 LOGE("failed to get storage info of subtitle path");
8435 result = MM_ERROR_PLAYER_INVALID_URI;
8439 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8440 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8442 if (!strcmp(filepath, subtitle_uri)) {
8443 LOGD("subtitle path is not changed");
8446 if (mm_player_set_attribute((MMHandleType)player, NULL,
8447 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8448 LOGE("failed to set attribute");
8453 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8454 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8455 player->subtitle_language_list = NULL;
8456 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8458 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8459 if (ret != GST_STATE_CHANGE_SUCCESS) {
8460 LOGE("failed to change state of textbin to READY");
8461 result = MM_ERROR_PLAYER_INTERNAL;
8465 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8466 if (ret != GST_STATE_CHANGE_SUCCESS) {
8467 LOGE("failed to change state of subparse to READY");
8468 result = MM_ERROR_PLAYER_INTERNAL;
8472 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8473 if (ret != GST_STATE_CHANGE_SUCCESS) {
8474 LOGE("failed to change state of filesrc to READY");
8475 result = MM_ERROR_PLAYER_INTERNAL;
8479 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8481 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8483 charset = _mmplayer_get_charset(filepath);
8485 LOGD("detected charset is %s", charset);
8486 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8489 result = _mmplayer_sync_subtitle_pipeline(player);
8496 /* API to switch between external subtitles */
8498 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8500 int result = MM_ERROR_NONE;
8501 mmplayer_t *player = (mmplayer_t *)hplayer;
8506 /* check player handle */
8507 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8509 /* filepath can be null in idle state */
8511 /* check file path */
8512 if ((path = strstr(filepath, "file://")))
8513 result = _mmplayer_exist_file_path(path + 7);
8515 result = _mmplayer_exist_file_path(filepath);
8517 if (result != MM_ERROR_NONE) {
8518 LOGE("invalid subtitle path 0x%X", result);
8519 return result; /* file not found or permission denied */
8523 if (!player->pipeline) {
8525 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8526 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8527 LOGE("failed to set attribute");
8528 return MM_ERROR_PLAYER_INTERNAL;
8531 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8532 /* check filepath */
8533 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8535 if (!__mmplayer_check_subtitle(player)) {
8536 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8537 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8538 LOGE("failed to set attribute");
8539 return MM_ERROR_PLAYER_INTERNAL;
8542 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8543 LOGE("fail to create text pipeline");
8544 return MM_ERROR_PLAYER_INTERNAL;
8547 result = _mmplayer_sync_subtitle_pipeline(player);
8549 result = __mmplayer_change_external_subtitle_language(player, filepath);
8552 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8553 player->is_external_subtitle_added_now = TRUE;
8555 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8556 if (!player->subtitle_language_list) {
8557 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8558 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8559 LOGW("subtitle language list is not updated yet");
8561 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8569 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8571 guint active_idx = 0;
8572 GstStream *stream = NULL;
8573 GList *streams = NULL;
8574 GstCaps *caps = NULL;
8577 LOGD("Switching Streams... type: %d, index: %d", type, index);
8579 player->track[type].active_track_index = index;
8581 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8582 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8583 LOGD("track type:%d, total: %d, active: %d", i,
8584 player->track[i].total_track_num, player->track[i].active_track_index);
8585 if (player->track[i].total_track_num > 0 &&
8586 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8587 active_idx = player->track[i].active_track_index;
8588 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8589 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8590 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8592 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8593 caps = gst_stream_get_caps(stream);
8595 _mmplayer_set_audio_attrs(player, caps);
8596 gst_caps_unref(caps);
8603 LOGD("send select stream event");
8604 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8605 gst_event_new_select_streams(streams));
8606 g_list_free(streams);
8609 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8610 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8611 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8613 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8614 pos_nsec = player->last_position;
8616 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8618 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8619 player->playback_rate, GST_FORMAT_TIME,
8620 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8621 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8622 LOGW("failed to seek");
8623 return MM_ERROR_PLAYER_INTERNAL;
8628 return MM_ERROR_NONE;
8632 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8634 int result = MM_ERROR_NONE;
8635 gchar *change_pad_name = NULL;
8636 GstPad *sinkpad = NULL;
8637 mmplayer_gst_element_t *mainbin = NULL;
8638 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8639 GstCaps *caps = NULL;
8640 gint total_track_num = 0;
8644 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8645 MM_ERROR_PLAYER_NOT_INITIALIZED);
8647 LOGD("Change Track(%d) to %d", type, index);
8649 mainbin = player->pipeline->mainbin;
8651 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8652 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8653 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8654 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8656 /* Changing Video Track is not supported. */
8657 LOGE("Track Type Error");
8661 if (mainbin[elem_idx].gst == NULL) {
8662 result = MM_ERROR_PLAYER_NO_OP;
8663 LOGD("Req track doesn't exist");
8667 total_track_num = player->track[type].total_track_num;
8668 if (total_track_num <= 0) {
8669 result = MM_ERROR_PLAYER_NO_OP;
8670 LOGD("Language list is not available");
8674 if ((index < 0) || (index >= total_track_num)) {
8675 result = MM_ERROR_INVALID_ARGUMENT;
8676 LOGD("Not a proper index : %d", index);
8680 /*To get the new pad from the selector*/
8681 change_pad_name = g_strdup_printf("sink_%u", index);
8682 if (change_pad_name == NULL) {
8683 result = MM_ERROR_PLAYER_INTERNAL;
8684 LOGD("Pad does not exists");
8688 LOGD("new active pad name: %s", change_pad_name);
8690 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8691 if (sinkpad == NULL) {
8692 LOGD("sinkpad is NULL");
8693 result = MM_ERROR_PLAYER_INTERNAL;
8697 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8698 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8700 caps = gst_pad_get_current_caps(sinkpad);
8701 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8704 gst_object_unref(sinkpad);
8706 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8707 _mmplayer_set_audio_attrs(player, caps);
8710 gst_caps_unref(caps);
8713 MMPLAYER_FREEIF(change_pad_name);
8718 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8720 int result = MM_ERROR_NONE;
8721 mmplayer_t *player = NULL;
8722 mmplayer_gst_element_t *mainbin = NULL;
8724 gint current_active_index = 0;
8726 GstState current_state = GST_STATE_VOID_PENDING;
8731 player = (mmplayer_t *)hplayer;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_PLAYER_NOT_INITIALIZED);
8735 if (!player->pipeline) {
8736 LOGE("Track %d pre setting -> %d", type, index);
8738 player->track[type].active_track_index = index;
8742 mainbin = player->pipeline->mainbin;
8744 current_active_index = player->track[type].active_track_index;
8746 /*If index is same as running index no need to change the pad*/
8747 if (current_active_index == index)
8750 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8751 result = MM_ERROR_PLAYER_INVALID_STATE;
8755 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8756 if (current_state < GST_STATE_PAUSED) {
8757 result = MM_ERROR_PLAYER_INVALID_STATE;
8758 LOGW("Pipeline not in proper state");
8762 if (MMPLAYER_USE_DECODEBIN(player))
8763 result = __mmplayer_change_selector_pad(player, type, index);
8765 result = __mmplayer_switch_stream(player, type, index);
8767 if (result != MM_ERROR_NONE) {
8768 LOGE("failed to change track");
8772 player->track[type].active_track_index = index;
8774 if (MMPLAYER_USE_DECODEBIN(player)) {
8775 GstEvent *event = NULL;
8776 if (current_state == GST_STATE_PLAYING) {
8777 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8778 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8779 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8781 _mmplayer_gst_send_event_to_sink(player, event);
8783 result = MM_ERROR_PLAYER_INTERNAL;
8794 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8796 mmplayer_t *player = (mmplayer_t *)hplayer;
8800 /* check player handle */
8801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8803 *silent = player->set_mode.subtitle_off;
8805 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8809 return MM_ERROR_NONE;
8813 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8815 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8816 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8818 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8819 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8823 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8824 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8825 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8826 mmplayer_dump_t *dump_s;
8827 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8828 if (dump_s == NULL) {
8829 LOGE("malloc fail");
8833 dump_s->dump_element_file = NULL;
8834 dump_s->dump_pad = NULL;
8835 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8837 if (dump_s->dump_pad) {
8838 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8839 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]);
8840 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8841 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);
8842 /* add list for removed buffer probe and close FILE */
8843 player->dump_list = g_list_append(player->dump_list, dump_s);
8844 LOGD("%s sink pad added buffer probe for dump", factory_name);
8847 MMPLAYER_FREEIF(dump_s);
8848 LOGE("failed to get %s sink pad added", factory_name);
8855 static GstPadProbeReturn
8856 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8858 FILE *dump_data = (FILE *)u_data;
8860 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8861 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8863 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8865 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8867 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8869 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8871 gst_buffer_unmap(buffer, &probe_info);
8873 return GST_PAD_PROBE_OK;
8877 __mmplayer_release_dump_list(GList *dump_list)
8879 GList *d_list = dump_list;
8884 for (; d_list; d_list = g_list_next(d_list)) {
8885 mmplayer_dump_t *dump_s = d_list->data;
8886 if (dump_s->dump_pad) {
8887 if (dump_s->probe_handle_id)
8888 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8889 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8891 if (dump_s->dump_element_file) {
8892 fclose(dump_s->dump_element_file);
8893 dump_s->dump_element_file = NULL;
8895 MMPLAYER_FREEIF(dump_s);
8897 g_list_free(dump_list);
8902 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8904 mmplayer_t *player = (mmplayer_t *)hplayer;
8908 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8909 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8911 *exist = (bool)player->has_closed_caption;
8915 return MM_ERROR_NONE;
8919 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8924 LOGD("unref internal gst buffer %p", buffer);
8926 gst_buffer_unref((GstBuffer *)buffer);
8933 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8935 mmplayer_t *player = (mmplayer_t *)hplayer;
8939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8940 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8942 if (MMPLAYER_IS_STREAMING(player))
8943 *timeout = (int)player->ini.live_state_change_timeout;
8945 *timeout = (int)player->ini.localplayback_state_change_timeout;
8947 LOGD("timeout = %d", *timeout);
8950 return MM_ERROR_NONE;
8954 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8958 MMPLAYER_RETURN_IF_FAIL(player);
8960 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8962 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8963 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8964 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8965 player->storage_info[i].id = -1;
8966 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8968 if (path_type != MMPLAYER_PATH_MAX)
8977 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8979 int ret = MM_ERROR_NONE;
8980 mmplayer_t *player = (mmplayer_t *)hplayer;
8981 MMMessageParamType msg_param = {0, };
8984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8986 LOGW("state changed storage %d:%d", id, state);
8988 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8989 return MM_ERROR_NONE;
8991 /* FIXME: text path should be handled separately. */
8992 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8993 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8994 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8995 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8996 LOGW("external storage is removed");
8998 if (player->msg_posted == FALSE) {
8999 memset(&msg_param, 0, sizeof(MMMessageParamType));
9000 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9001 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9002 player->msg_posted = TRUE;
9005 /* unrealize the player */
9006 ret = _mmplayer_unrealize(hplayer);
9007 if (ret != MM_ERROR_NONE)
9008 LOGE("failed to unrealize");
9016 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9018 int ret = MM_ERROR_NONE;
9019 mmplayer_t *player = (mmplayer_t *)hplayer;
9020 int idx = 0, total = 0;
9021 gchar *result = NULL, *tmp = NULL;
9024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9025 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9027 total = *num = g_list_length(player->adaptive_info.var_list);
9029 LOGW("There is no stream variant info.");
9033 result = g_strdup("");
9034 for (idx = 0 ; idx < total ; idx++) {
9035 stream_variant_t *v_data = NULL;
9036 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9039 gchar data[64] = {0};
9040 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9042 tmp = g_strconcat(result, data, NULL);
9046 LOGW("There is no variant data in %d", idx);
9051 *var_info = (char *)result;
9053 LOGD("variant info %d:%s", *num, *var_info);
9059 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9061 int ret = MM_ERROR_NONE;
9062 mmplayer_t *player = (mmplayer_t *)hplayer;
9065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9067 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9069 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9070 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9071 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9073 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9074 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9075 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9076 "max-bitrate", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9078 /* FIXME: seek to current position for applying new variant limitation */
9087 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9089 int ret = MM_ERROR_NONE;
9090 mmplayer_t *player = (mmplayer_t *)hplayer;
9093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9094 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9096 *bandwidth = player->adaptive_info.limit.bandwidth;
9097 *width = player->adaptive_info.limit.width;
9098 *height = player->adaptive_info.limit.height;
9100 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9107 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9109 int ret = MM_ERROR_NONE;
9110 mmplayer_t *player = (mmplayer_t *)hplayer;
9113 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9115 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9117 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9119 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9120 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9121 else /* live case */
9122 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9124 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9131 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9133 #define IDX_FIRST_SW_CODEC 0
9134 mmplayer_t *player = (mmplayer_t *)hplayer;
9135 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9136 const char *attr_name = NULL;
9137 const char *default_type = NULL;
9138 const char *element_hw = NULL;
9139 const char *element_sw = NULL;
9142 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9144 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9146 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9147 switch (stream_type) {
9148 case MM_PLAYER_STREAM_TYPE_AUDIO:
9149 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9150 default_type = player->ini.audiocodec_default_type;
9151 element_hw = player->ini.audiocodec_element_hw;
9152 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9154 case MM_PLAYER_STREAM_TYPE_VIDEO:
9155 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9156 default_type = player->ini.videocodec_default_type;
9157 element_hw = player->ini.videocodec_element_hw;
9158 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9161 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9162 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9166 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9168 if (!strcmp(default_type, "sw"))
9169 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9171 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9173 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9174 codec_type = default_codec_type;
9176 /* to support codec selection, codec info have to be added in ini file.
9177 in case of hw codec is selected, filter elements should be applied
9178 depending on the hw capabilities. */
9179 if (codec_type != default_codec_type) {
9180 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9181 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9182 LOGE("There is no codec for type %d", codec_type);
9183 return MM_ERROR_PLAYER_NO_OP;
9186 LOGD("sorting is required");
9187 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9188 player->need_audio_dec_sorting = TRUE;
9190 player->need_video_dec_sorting = TRUE;
9193 LOGD("update %s codec_type to %d", attr_name, codec_type);
9194 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9197 return MM_ERROR_NONE;
9201 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9203 mmplayer_t *player = (mmplayer_t *)hplayer;
9204 GstElement *rg_vol_element = NULL;
9208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9210 player->sound.rg_enable = enabled;
9212 /* just hold rgvolume enable value if pipeline is not ready */
9213 if (!player->pipeline || !player->pipeline->audiobin) {
9214 LOGD("pipeline is not ready. holding rgvolume enable value");
9215 return MM_ERROR_NONE;
9218 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9220 if (!rg_vol_element) {
9221 LOGD("rgvolume element is not created");
9222 return MM_ERROR_PLAYER_INTERNAL;
9226 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9228 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9232 return MM_ERROR_NONE;
9236 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9238 mmplayer_t *player = (mmplayer_t *)hplayer;
9239 GstElement *rg_vol_element = NULL;
9240 gboolean enable = FALSE;
9244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9245 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9247 /* just hold enable_rg value if pipeline is not ready */
9248 if (!player->pipeline || !player->pipeline->audiobin) {
9249 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9250 *enabled = player->sound.rg_enable;
9251 return MM_ERROR_NONE;
9254 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9256 if (!rg_vol_element) {
9257 LOGD("rgvolume element is not created");
9258 return MM_ERROR_PLAYER_INTERNAL;
9261 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9262 *enabled = (bool)enable;
9266 return MM_ERROR_NONE;
9270 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9272 mmplayer_t *player = (mmplayer_t *)hplayer;
9273 MMHandleType attrs = 0;
9275 int ret = MM_ERROR_NONE;
9279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9281 attrs = MMPLAYER_GET_ATTRS(player);
9282 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9284 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9286 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9287 return MM_ERROR_PLAYER_INTERNAL;
9290 player->video_roi.scale_x = scale_x;
9291 player->video_roi.scale_y = scale_y;
9292 player->video_roi.scale_width = scale_width;
9293 player->video_roi.scale_height = scale_height;
9295 /* check video sinkbin is created */
9296 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9297 return MM_ERROR_NONE;
9299 if (!gst_video_overlay_set_video_roi_area(
9300 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9301 scale_x, scale_y, scale_width, scale_height))
9302 ret = MM_ERROR_PLAYER_INTERNAL;
9304 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9305 scale_x, scale_y, scale_width, scale_height);
9313 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9315 mmplayer_t *player = (mmplayer_t *)hplayer;
9316 int ret = MM_ERROR_NONE;
9320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9321 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9323 *scale_x = player->video_roi.scale_x;
9324 *scale_y = player->video_roi.scale_y;
9325 *scale_width = player->video_roi.scale_width;
9326 *scale_height = player->video_roi.scale_height;
9328 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9329 *scale_x, *scale_y, *scale_width, *scale_height);
9335 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9337 mmplayer_t *player = (mmplayer_t *)hplayer;
9341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9343 player->client_pid = pid;
9345 LOGD("client pid[%d] %p", pid, player);
9349 return MM_ERROR_NONE;
9353 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9355 mmplayer_t *player = (mmplayer_t *)hplayer;
9356 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9357 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9362 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9365 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9367 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9369 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9370 return MM_ERROR_NONE;
9372 /* in case of audio codec default type is HW */
9374 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9375 if (player->ini.support_audio_effect)
9376 return MM_ERROR_NONE;
9377 elem_id = MMPLAYER_A_FILTER;
9379 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9380 if (player->ini.support_replaygain_control)
9381 return MM_ERROR_NONE;
9382 elem_id = MMPLAYER_A_RGVOL;
9384 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9385 if (player->ini.support_pitch_control)
9386 return MM_ERROR_NONE;
9387 elem_id = MMPLAYER_A_PITCH;
9389 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9390 if (player->ini.support_audio_effect)
9391 return MM_ERROR_NONE;
9393 /* default case handling is not required */
9396 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9397 LOGW("audio control option [%d] is not available", opt);
9400 /* setting pcm exporting option is allowed before READY state */
9401 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9402 return MM_ERROR_PLAYER_INVALID_STATE;
9404 /* check whether the audio filter exist or not after READY state,
9405 because the sw codec could be added during auto-plugging in some cases */
9406 if (!player->pipeline ||
9407 !player->pipeline->audiobin ||
9408 !player->pipeline->audiobin[elem_id].gst) {
9409 LOGW("there is no audio elem [%d]", elem_id);
9414 LOGD("audio control opt %d, available %d", opt, *available);
9418 return MM_ERROR_NONE;
9422 __mmplayer_update_duration_value(mmplayer_t *player)
9424 gboolean ret = FALSE;
9425 gint64 dur_nsec = 0;
9426 LOGD("try to update duration");
9428 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9429 player->duration = dur_nsec;
9430 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9434 if (player->duration < 0) {
9435 LOGW("duration is Non-Initialized !!!");
9436 player->duration = 0;
9439 /* update streaming service type */
9440 player->streaming_type = _mmplayer_get_stream_service_type(player);
9442 /* check duration is OK */
9443 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9444 /* FIXIT : find another way to get duration here. */
9445 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9451 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9453 /* update audio params
9454 NOTE : We need original audio params and it can be only obtained from src pad of audio
9455 decoder. Below code only valid when we are not using 'resampler' just before
9456 'audioconverter'. */
9457 GstCaps *caps_a = NULL;
9459 gint samplerate = 0, channels = 0;
9460 GstStructure *p = NULL;
9461 GstElement *aconv = NULL;
9463 LOGD("try to update audio attrs");
9465 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9467 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9468 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9469 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9470 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9472 LOGE("there is no audio converter");
9476 pad = gst_element_get_static_pad(aconv, "sink");
9479 LOGW("failed to get pad from audio converter");
9483 caps_a = gst_pad_get_current_caps(pad);
9485 LOGW("not ready to get audio caps");
9486 gst_object_unref(pad);
9490 p = gst_caps_get_structure(caps_a, 0);
9491 gst_structure_get_int(p, "rate", &samplerate);
9492 gst_structure_get_int(p, "channels", &channels);
9494 mm_player_set_attribute((MMHandleType)player, NULL,
9495 "content_audio_samplerate", samplerate,
9496 "content_audio_channels", channels, NULL);
9498 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9500 gst_caps_unref(caps_a);
9501 gst_object_unref(pad);
9507 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9509 LOGD("try to update video attrs");
9511 GstCaps *caps_v = NULL;
9515 GstStructure *p = NULL;
9517 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9518 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9520 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9522 LOGD("no videosink sink pad");
9526 caps_v = gst_pad_get_current_caps(pad);
9527 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9528 if (!caps_v && player->v_stream_caps) {
9529 caps_v = player->v_stream_caps;
9530 gst_caps_ref(caps_v);
9534 LOGD("no negotiated caps from videosink");
9535 gst_object_unref(pad);
9539 p = gst_caps_get_structure(caps_v, 0);
9540 gst_structure_get_int(p, "width", &width);
9541 gst_structure_get_int(p, "height", &height);
9543 mm_player_set_attribute((MMHandleType)player, NULL,
9544 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9546 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9548 SECURE_LOGD("width : %d height : %d", width, height);
9550 gst_caps_unref(caps_v);
9551 gst_object_unref(pad);
9554 mm_player_set_attribute((MMHandleType)player, NULL,
9555 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9556 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9563 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9565 gboolean ret = FALSE;
9566 guint64 data_size = 0;
9570 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9571 if (!player->duration)
9574 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9575 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9576 if (stat(path, &sb) == 0)
9577 data_size = (guint64)sb.st_size;
9579 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9580 data_size = player->http_content_size;
9583 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9586 guint64 bitrate = 0;
9587 guint64 msec_dur = 0;
9589 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9591 bitrate = data_size * 8 * 1000 / msec_dur;
9592 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9593 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9594 mm_player_set_attribute((MMHandleType)player, NULL,
9595 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9598 LOGD("player duration is less than 0");
9602 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9603 if (player->total_bitrate) {
9604 mm_player_set_attribute((MMHandleType)player, NULL,
9605 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9614 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9616 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9617 data->uri_type = uri_type;
9621 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9623 int ret = MM_ERROR_PLAYER_INVALID_URI;
9625 char *buffer = NULL;
9626 char *seperator = strchr(path, ',');
9627 char ext[100] = {0,}, size[100] = {0,};
9630 if ((buffer = strstr(path, "ext="))) {
9631 buffer += strlen("ext=");
9633 if (strlen(buffer)) {
9634 strncpy(ext, buffer, 99);
9636 if ((seperator = strchr(ext, ','))
9637 || (seperator = strchr(ext, ' '))
9638 || (seperator = strchr(ext, '\0'))) {
9639 seperator[0] = '\0';
9644 if ((buffer = strstr(path, "size="))) {
9645 buffer += strlen("size=");
9647 if (strlen(buffer) > 0) {
9648 strncpy(size, buffer, 99);
9650 if ((seperator = strchr(size, ','))
9651 || (seperator = strchr(size, ' '))
9652 || (seperator = strchr(size, '\0'))) {
9653 seperator[0] = '\0';
9656 mem_size = atoi(size);
9661 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9663 if (mem_size && param) {
9664 if (data->input_mem.buf)
9665 free(data->input_mem.buf);
9666 data->input_mem.buf = malloc(mem_size);
9668 if (data->input_mem.buf) {
9669 memcpy(data->input_mem.buf, param, mem_size);
9670 data->input_mem.len = mem_size;
9671 ret = MM_ERROR_NONE;
9673 LOGE("failed to alloc mem %d", mem_size);
9674 ret = MM_ERROR_PLAYER_INTERNAL;
9677 data->input_mem.offset = 0;
9678 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9685 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9687 gchar *location = NULL;
9690 int ret = MM_ERROR_NONE;
9692 if ((path = strstr(uri, "file://"))) {
9693 location = g_filename_from_uri(uri, NULL, &err);
9694 if (!location || (err != NULL)) {
9695 LOGE("Invalid URI '%s' for filesrc: %s", path,
9696 (err != NULL) ? err->message : "unknown error");
9700 MMPLAYER_FREEIF(location);
9702 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9703 return MM_ERROR_PLAYER_INVALID_URI;
9705 LOGD("path from uri: %s", location);
9708 path = (location != NULL) ? (location) : ((char *)uri);
9711 ret = _mmplayer_exist_file_path(path);
9713 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9714 if (ret == MM_ERROR_NONE) {
9715 if (_mmplayer_is_sdp_file(path)) {
9716 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9717 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9718 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9720 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9721 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9723 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9724 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9726 LOGE("invalid uri, could not play..");
9727 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9730 MMPLAYER_FREEIF(location);
9735 static mmplayer_video_decoded_data_info_t *
9736 __mmplayer_create_stream_from_pad(GstPad *pad)
9738 GstCaps *caps = NULL;
9739 GstStructure *structure = NULL;
9740 unsigned int fourcc = 0;
9741 const gchar *string_format = NULL;
9742 mmplayer_video_decoded_data_info_t *stream = NULL;
9744 MMPixelFormatType format;
9747 caps = gst_pad_get_current_caps(pad);
9749 LOGE("Caps is NULL.");
9754 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9756 structure = gst_caps_get_structure(caps, 0);
9757 gst_structure_get_int(structure, "width", &width);
9758 gst_structure_get_int(structure, "height", &height);
9759 string_format = gst_structure_get_string(structure, "format");
9762 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9763 format = _mmplayer_get_pixtype(fourcc);
9764 gst_video_info_from_caps(&info, caps);
9765 gst_caps_unref(caps);
9768 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9769 LOGE("Wrong condition!!");
9773 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9775 LOGE("failed to alloc mem for video data");
9779 stream->width = width;
9780 stream->height = height;
9781 stream->format = format;
9782 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9788 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9790 unsigned int pitch = 0;
9791 unsigned int size = 0;
9793 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9796 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9797 bo = gst_tizen_memory_get_bos(mem, index);
9799 stream->bo[index] = tbm_bo_ref(bo);
9801 LOGE("failed to get bo for index %d", index);
9804 for (index = 0; index < stream->plane_num; index++) {
9805 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9806 stream->stride[index] = pitch;
9808 stream->elevation[index] = size / pitch;
9810 stream->elevation[index] = stream->height;
9815 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9817 if (stream->format == MM_PIXEL_FORMAT_I420) {
9818 int ret = TBM_SURFACE_ERROR_NONE;
9819 tbm_surface_h surface;
9820 tbm_surface_info_s info;
9822 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9824 ret = tbm_surface_get_info(surface, &info);
9825 if (ret != TBM_SURFACE_ERROR_NONE) {
9826 tbm_surface_destroy(surface);
9830 tbm_surface_destroy(surface);
9831 stream->stride[0] = info.planes[0].stride;
9832 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9833 stream->stride[1] = info.planes[1].stride;
9834 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9835 stream->stride[2] = info.planes[2].stride;
9836 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9837 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9838 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9839 stream->stride[0] = stream->width * 4;
9840 stream->elevation[0] = stream->height;
9841 stream->bo_size = stream->stride[0] * stream->height;
9843 LOGE("Not support format %d", stream->format);
9851 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9853 tbm_bo_handle thandle;
9855 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9856 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9857 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9861 unsigned char *src = NULL;
9862 unsigned char *dest = NULL;
9863 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9865 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9867 LOGE("fail to gst_memory_map");
9871 if (!mapinfo.data) {
9872 LOGE("data pointer is wrong");
9876 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9877 if (!stream->bo[0]) {
9878 LOGE("Fail to tbm_bo_alloc!!");
9882 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9884 LOGE("thandle pointer is wrong");
9888 if (stream->format == MM_PIXEL_FORMAT_I420) {
9889 src_stride[0] = GST_ROUND_UP_4(stream->width);
9890 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9891 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9892 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9895 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9896 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9898 for (i = 0; i < 3; i++) {
9899 src = mapinfo.data + src_offset[i];
9900 dest = thandle.ptr + dest_offset[i];
9905 for (j = 0; j < stream->height >> k; j++) {
9906 memcpy(dest, src, stream->width>>k);
9907 src += src_stride[i];
9908 dest += stream->stride[i];
9911 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9912 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9914 LOGE("Not support format %d", stream->format);
9918 tbm_bo_unmap(stream->bo[0]);
9919 gst_memory_unmap(mem, &mapinfo);
9925 tbm_bo_unmap(stream->bo[0]);
9928 gst_memory_unmap(mem, &mapinfo);
9934 __mmplayer_set_pause_state(mmplayer_t *player)
9936 if (player->sent_bos)
9939 /* rtsp case, get content attrs by GstMessage */
9940 if (MMPLAYER_IS_RTSP_STREAMING(player))
9943 /* it's first time to update all content attrs. */
9944 _mmplayer_update_content_attrs(player, ATTR_ALL);
9948 __mmplayer_set_playing_state(mmplayer_t *player)
9950 gchar *audio_codec = NULL;
9952 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9953 /* initialize because auto resume is done well. */
9954 player->resumed_by_rewind = FALSE;
9955 player->playback_rate = 1.0;
9958 if (player->sent_bos)
9961 /* try to get content metadata */
9963 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9964 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9965 * legacy mmfw-player api
9967 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9969 if ((player->cmd == MMPLAYER_COMMAND_START)
9970 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9971 __mmplayer_handle_missed_plugin(player);
9974 /* check audio codec field is set or not
9975 * we can get it from typefinder or codec's caps.
9977 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9979 /* The codec format can't be sent for audio only case like amr, mid etc.
9980 * Because, parser don't make related TAG.
9981 * So, if it's not set yet, fill it with found data.
9984 if (g_strrstr(player->type_caps_str, "audio/midi"))
9985 audio_codec = "MIDI";
9986 else if (g_strrstr(player->type_caps_str, "audio/x-amr"))
9987 audio_codec = "AMR";
9988 else if (g_strrstr(player->type_caps_str, "audio/mpeg")
9989 && !g_strrstr(player->type_caps_str, "mpegversion=(int)1"))
9990 audio_codec = "AAC";
9992 audio_codec = "unknown";
9994 if (mm_player_set_attribute((MMHandleType)player, NULL,
9995 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9996 LOGE("failed to set attribute");
9998 LOGD("set audio codec type with caps");