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 #define MQ_UNLINKED_CACHE_TIME (500 * GST_MSECOND)
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
146 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
147 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static void __mmplayer_release_misc(mmplayer_t *player);
152 static void __mmplayer_release_misc_post(mmplayer_t *player);
153 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
154 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
157 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
159 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
160 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
161 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
162 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
164 static gpointer __mmplayer_gapless_play_thread(gpointer data);
165 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
166 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_release_dump_list(GList *dump_list);
168 static int __mmplayer_gst_realize(mmplayer_t *player);
169 static int __mmplayer_gst_unrealize(mmplayer_t *player);
170 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
171 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
174 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
175 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
176 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
177 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
178 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
179 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
180 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
181 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
182 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
183 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
184 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
185 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
187 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
189 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
190 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
191 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
193 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
194 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
195 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
196 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
198 static void __mmplayer_set_pause_state(mmplayer_t *player);
199 static void __mmplayer_set_playing_state(mmplayer_t *player);
200 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
201 /*===========================================================================================
203 | FUNCTION DEFINITIONS |
205 ========================================================================================== */
207 /* This function should be called after the pipeline goes PAUSED or higher
210 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
212 static gboolean has_duration = FALSE;
213 static gboolean has_video_attrs = FALSE;
214 static gboolean has_audio_attrs = FALSE;
215 static gboolean has_bitrate = FALSE;
216 gboolean missing_only = FALSE;
217 gboolean all = FALSE;
218 MMHandleType attrs = 0;
222 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
224 /* check player state here */
225 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
226 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
227 /* give warning now only */
228 LOGW("be careful. content attributes may not available in this state ");
231 /* get content attribute first */
232 attrs = MMPLAYER_GET_ATTRS(player);
234 LOGE("cannot get content attribute");
238 /* get update flag */
240 if (flag & ATTR_MISSING_ONLY) {
242 LOGD("updating missed attr only");
245 if (flag & ATTR_ALL) {
247 has_duration = FALSE;
248 has_video_attrs = FALSE;
249 has_audio_attrs = FALSE;
252 LOGD("updating all attrs");
255 if (missing_only && all) {
256 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
257 missing_only = FALSE;
260 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
261 has_duration = __mmplayer_update_duration_value(player);
263 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
264 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
266 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
267 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
269 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
270 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
278 _mmplayer_get_stream_service_type(mmplayer_t *player)
280 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
284 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
286 player->pipeline->mainbin &&
287 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
288 STREAMING_SERVICE_NONE);
290 /* streaming service type if streaming */
291 if (!MMPLAYER_IS_STREAMING(player))
292 return STREAMING_SERVICE_NONE;
294 streaming_type = (player->duration == 0) ?
295 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
297 switch (streaming_type) {
298 case STREAMING_SERVICE_LIVE:
299 LOGD("it's live streaming");
301 case STREAMING_SERVICE_VOD:
302 LOGD("it's vod streaming");
305 LOGE("should not get here");
311 return streaming_type;
314 /* this function sets the player state and also report
315 * it to application by calling callback function
318 _mmplayer_set_state(mmplayer_t *player, int state)
320 MMMessageParamType msg = {0, };
322 MMPLAYER_RETURN_IF_FAIL(player);
324 if (MMPLAYER_CURRENT_STATE(player) == state) {
325 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
326 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
330 /* update player states */
331 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
332 MMPLAYER_CURRENT_STATE(player) = state;
334 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
335 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
338 MMPLAYER_PRINT_STATE(player);
340 switch (MMPLAYER_CURRENT_STATE(player)) {
341 case MM_PLAYER_STATE_NULL:
342 case MM_PLAYER_STATE_READY:
344 case MM_PLAYER_STATE_PAUSED:
345 __mmplayer_set_pause_state(player);
347 case MM_PLAYER_STATE_PLAYING:
348 __mmplayer_set_playing_state(player);
350 case MM_PLAYER_STATE_NONE:
352 LOGW("invalid target state, there is nothing to do.");
357 /* post message to application */
358 if (MMPLAYER_TARGET_STATE(player) == state) {
359 /* fill the message with state of player */
360 msg.union_type = MM_MSG_UNION_STATE;
361 msg.state.previous = MMPLAYER_PREV_STATE(player);
362 msg.state.current = MMPLAYER_CURRENT_STATE(player);
364 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
366 /* state changed by resource callback */
367 if (player->interrupted_by_resource)
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
369 else /* state changed by usecase */
370 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
373 LOGD("intermediate state, do nothing.");
374 MMPLAYER_PRINT_STATE(player);
378 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
379 && !player->sent_bos) {
380 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
381 player->sent_bos = TRUE;
388 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
390 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
391 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
395 LOGD("incoming command : %d ", command);
397 current_state = MMPLAYER_CURRENT_STATE(player);
398 pending_state = MMPLAYER_PENDING_STATE(player);
400 MMPLAYER_PRINT_STATE(player);
403 case MMPLAYER_COMMAND_CREATE:
405 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
407 if (current_state == MM_PLAYER_STATE_NULL ||
408 current_state == MM_PLAYER_STATE_READY ||
409 current_state == MM_PLAYER_STATE_PAUSED ||
410 current_state == MM_PLAYER_STATE_PLAYING)
415 case MMPLAYER_COMMAND_DESTROY:
417 /* destroy can called anytime */
419 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
423 case MMPLAYER_COMMAND_REALIZE:
425 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
427 if (pending_state != MM_PLAYER_STATE_NONE) {
430 /* need ready state to realize */
431 if (current_state == MM_PLAYER_STATE_READY)
434 if (current_state != MM_PLAYER_STATE_NULL)
440 case MMPLAYER_COMMAND_UNREALIZE:
442 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
444 if (current_state == MM_PLAYER_STATE_NULL)
449 case MMPLAYER_COMMAND_START:
451 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
453 if (pending_state == MM_PLAYER_STATE_NONE) {
454 if (current_state == MM_PLAYER_STATE_PLAYING)
456 else if (current_state != MM_PLAYER_STATE_READY &&
457 current_state != MM_PLAYER_STATE_PAUSED)
459 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
461 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
462 LOGD("player is going to paused state, just change the pending state as playing");
469 case MMPLAYER_COMMAND_STOP:
471 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
473 if (current_state == MM_PLAYER_STATE_READY)
476 /* need playing/paused state to stop */
477 if (current_state != MM_PLAYER_STATE_PLAYING &&
478 current_state != MM_PLAYER_STATE_PAUSED)
483 case MMPLAYER_COMMAND_PAUSE:
485 if (MMPLAYER_IS_LIVE_STREAMING(player))
488 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
489 goto NOT_COMPLETED_SEEK;
491 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
493 if (pending_state == MM_PLAYER_STATE_NONE) {
494 if (current_state == MM_PLAYER_STATE_PAUSED)
496 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
498 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
501 if (current_state == MM_PLAYER_STATE_PAUSED)
502 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
509 case MMPLAYER_COMMAND_RESUME:
511 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
512 goto NOT_COMPLETED_SEEK;
514 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
516 if (pending_state == MM_PLAYER_STATE_NONE) {
517 if (current_state == MM_PLAYER_STATE_PLAYING)
519 else if (current_state != MM_PLAYER_STATE_PAUSED)
521 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
523 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
524 LOGD("player is going to paused state, just change the pending state as playing");
534 player->cmd = command;
536 return MM_ERROR_NONE;
539 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
540 MMPLAYER_STATE_GET_NAME(current_state), command);
541 return MM_ERROR_PLAYER_INVALID_STATE;
544 LOGW("not completed seek");
545 return MM_ERROR_PLAYER_DOING_SEEK;
548 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
549 return MM_ERROR_PLAYER_NO_OP;
552 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
553 return MM_ERROR_PLAYER_NO_OP;
556 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
558 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
559 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
562 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
563 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
565 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
566 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
568 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
569 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
572 LOGE("invalid mmplayer resource type %d", type);
573 return MM_ERROR_PLAYER_INTERNAL;
576 if (player->hw_resource[type] != NULL) {
577 LOGD("[%d type] resource was already acquired", type);
578 return MM_ERROR_NONE;
581 LOGD("mark for acquire [%d type] resource", type);
582 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
583 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
584 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
585 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
586 return MM_ERROR_PLAYER_INTERNAL;
589 LOGD("commit [%d type] resource", type);
590 rm_ret = mm_resource_manager_commit(player->resource_manager);
591 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
592 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
593 return MM_ERROR_PLAYER_INTERNAL;
597 return MM_ERROR_NONE;
600 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
602 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
604 MMPLAYER_RETURN_IF_FAIL(player);
605 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
607 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
608 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
609 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
613 rm_ret = mm_resource_manager_commit(player->resource_manager);
614 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
615 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
618 /* de-initialize resource manager */
619 rm_ret = mm_resource_manager_destroy(player->resource_manager);
620 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
621 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
625 player->resource_manager = NULL;
627 LOGD("resource manager is destroyed");
630 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
632 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
636 if (player->hw_resource[type] == NULL) {
637 LOGD("there is no acquired [%d type] resource", type);
638 return MM_ERROR_NONE;
641 LOGD("mark for release [%d type] resource", type);
642 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
643 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
644 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
645 return MM_ERROR_PLAYER_INTERNAL;
648 player->hw_resource[type] = NULL;
650 LOGD("commit [%d type] resource", type);
651 rm_ret = mm_resource_manager_commit(player->resource_manager);
652 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
653 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
654 return MM_ERROR_PLAYER_INTERNAL;
658 return MM_ERROR_NONE;
662 __mmplayer_initialize_gapless_play(mmplayer_t *player)
668 player->smooth_streaming = FALSE;
669 player->videodec_linked = 0;
670 player->audiodec_linked = 0;
671 player->textsink_linked = 0;
672 player->is_external_subtitle_present = FALSE;
673 player->is_external_subtitle_added_now = FALSE;
674 player->not_supported_codec = MISSING_PLUGIN_NONE;
675 player->can_support_codec = FOUND_PLUGIN_NONE;
676 player->pending_seek.is_pending = false;
677 player->pending_seek.pos = 0;
678 player->msg_posted = FALSE;
679 player->has_many_types = FALSE;
680 player->no_more_pad = FALSE;
681 player->not_found_demuxer = 0;
682 player->seek_state = MMPLAYER_SEEK_NONE;
683 player->is_subtitle_force_drop = FALSE;
684 player->play_subtitle = FALSE;
685 player->adjust_subtitle_pos = 0;
687 player->total_bitrate = 0;
688 player->total_maximum_bitrate = 0;
690 _mmplayer_track_initialize(player);
691 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
693 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
694 player->bitrate[i] = 0;
695 player->maximum_bitrate[i] = 0;
698 if (player->v_stream_caps) {
699 gst_caps_unref(player->v_stream_caps);
700 player->v_stream_caps = NULL;
703 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
705 /* clean found audio decoders */
706 if (player->audio_decoders) {
707 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
708 player->audio_decoders = NULL;
711 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
716 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
718 LOGI("set pipeline reconfigure state %d", state);
719 MMPLAYER_RECONFIGURE_LOCK(player);
720 player->gapless.reconfigure = state;
721 if (!state) /* wake up the waiting job */
722 MMPLAYER_RECONFIGURE_SIGNAL(player);
723 MMPLAYER_RECONFIGURE_UNLOCK(player);
727 __mmplayer_gapless_play_thread(gpointer data)
729 mmplayer_t *player = (mmplayer_t *)data;
730 mmplayer_gst_element_t *mainbin = NULL;
732 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
734 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
735 while (!player->gapless_play_thread_exit) {
736 LOGD("gapless play thread started. waiting for signal.");
737 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
739 LOGD("reconfigure pipeline for gapless play.");
741 if (player->gapless_play_thread_exit) {
742 _mmplayer_set_reconfigure_state(player, FALSE);
743 LOGD("exiting gapless play thread");
747 mainbin = player->pipeline->mainbin;
749 if (MMPLAYER_USE_DECODEBIN(player)) {
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
756 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
757 mainbin[MMPLAYER_M_SRC].gst = NULL;
760 /* Initialize Player values */
761 __mmplayer_initialize_gapless_play(player);
763 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
765 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
771 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
773 GSource *source = NULL;
777 source = g_main_context_find_source_by_id(context, source_id);
778 if (source != NULL) {
779 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
780 g_source_destroy(source);
787 _mmplayer_watcher_removed_notify(gpointer data)
789 mmplayer_t *player = (mmplayer_t *)data;
790 MMPLAYER_RETURN_IF_FAIL(player);
792 MMPLAYER_BUS_WATCHER_LOCK(player);
793 player->bus_watcher = 0;
794 MMPLAYER_BUS_WATCHER_SIGNAL(player);
795 MMPLAYER_BUS_WATCHER_UNLOCK(player);
799 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
801 mmplayer_t *player = (mmplayer_t *)hplayer;
804 MMPLAYER_RETURN_IF_FAIL(player);
806 /* disconnecting bus watch */
807 if (player->bus_watcher > 0) {
808 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
809 MMPLAYER_BUS_WATCHER_LOCK(player);
810 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
811 while (player->bus_watcher > 0) {
812 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
813 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
814 player->bus_watcher);
818 MMPLAYER_BUS_WATCHER_UNLOCK(player);
819 g_mutex_clear(&player->bus_watcher_mutex);
820 g_cond_clear(&player->bus_watcher_cond);
827 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
829 mmplayer_t *player = (mmplayer_t *)hplayer;
830 GstMessage *msg = NULL;
831 GQueue *queue = NULL;
834 MMPLAYER_RETURN_IF_FAIL(player);
836 /* destroy the gst bus msg thread */
837 if (player->bus_msg_thread) {
838 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
839 player->bus_msg_thread_exit = TRUE;
840 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
841 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
843 LOGD("gst bus msg thread exit.");
844 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
845 player->bus_msg_thread = NULL;
847 g_mutex_clear(&player->bus_msg_thread_mutex);
848 g_cond_clear(&player->bus_msg_thread_cond);
851 g_mutex_lock(&player->bus_msg_q_lock);
852 queue = player->bus_msg_q;
853 while (!g_queue_is_empty(queue)) {
854 msg = (GstMessage *)g_queue_pop_head(queue);
859 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
860 gst_message_unref(msg);
862 g_mutex_unlock(&player->bus_msg_q_lock);
868 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
870 GstElement *parent = NULL;
872 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
873 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
876 MMPLAYER_FSINK_LOCK(player);
878 /* get parent of fakesink */
879 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
881 LOGD("fakesink already removed");
885 gst_element_set_locked_state(fakesink->gst, TRUE);
887 /* setting the state to NULL never returns async
888 * so no need to wait for completion of state transition
890 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
891 LOGE("fakesink state change failure!");
892 /* FIXIT : should I return here? or try to proceed to next? */
895 /* remove fakesink from it's parent */
896 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
897 LOGE("failed to remove fakesink");
899 gst_object_unref(parent);
904 gst_object_unref(parent);
906 LOGD("state-holder removed");
908 gst_element_set_locked_state(fakesink->gst, FALSE);
910 MMPLAYER_FSINK_UNLOCK(player);
915 gst_element_set_locked_state(fakesink->gst, FALSE);
917 MMPLAYER_FSINK_UNLOCK(player);
921 static GstPadProbeReturn
922 __mmplayer_gst_combiner_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
925 return GST_PAD_PROBE_OK;
929 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
931 gint64 stop_running_time = 0;
932 gint64 position_running_time = 0;
936 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
937 if ((player->gapless.update_segment[idx] == TRUE) ||
938 !(player->track[idx].event_probe_id)) {
940 LOGW("[%d] skip", idx);
945 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
947 gst_segment_to_running_time(&player->gapless.segment[idx],
948 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
949 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
951 gst_segment_to_running_time(&player->gapless.segment[idx],
952 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
954 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
956 gst_segment_to_running_time(&player->gapless.segment[idx],
957 GST_FORMAT_TIME, player->duration);
960 position_running_time =
961 gst_segment_to_running_time(&player->gapless.segment[idx],
962 GST_FORMAT_TIME, player->gapless.segment[idx].position);
964 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
965 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
967 GST_TIME_ARGS(stop_running_time),
968 GST_TIME_ARGS(position_running_time),
969 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
970 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
972 position_running_time = MAX(position_running_time, stop_running_time);
973 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
974 GST_FORMAT_TIME, player->gapless.segment[idx].start);
975 position_running_time = MAX(0, position_running_time);
976 position = MAX(position, position_running_time);
980 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
981 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
982 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
984 player->gapless.start_time[stream_type] += position;
990 static GstPadProbeReturn
991 __mmplayer_gst_combiner_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
993 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
994 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
995 mmplayer_t *player = (mmplayer_t *)data;
996 GstCaps *caps = NULL;
997 GstStructure *str = NULL;
998 const gchar *name = NULL;
999 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1000 gboolean caps_ret = TRUE;
1002 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1005 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1006 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1009 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1011 GstStream *stream = NULL;
1013 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START)
1016 gst_event_parse_stream (event, &stream);
1017 if (stream == NULL) {
1018 LOGW ("Got a STREAM_START event without a GstStream");
1022 name = gst_stream_type_get_name(gst_stream_get_stream_type(stream));
1023 gst_object_unref (stream);
1029 if (strstr(name, "audio")) {
1030 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1031 } else if (strstr(name, "video")) {
1032 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1034 /* text track is not supportable */
1035 LOGE("invalid name %s", name);
1039 switch (GST_EVENT_TYPE(event)) {
1042 /* in case of gapless, drop eos event not to send it to sink */
1043 if (player->gapless.reconfigure && !player->msg_posted) {
1044 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1045 ret = GST_PAD_PROBE_DROP;
1049 case GST_EVENT_STREAM_START:
1051 __mmplayer_gst_selector_update_start_time(player, stream_type);
1054 case GST_EVENT_FLUSH_STOP:
1056 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1057 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1058 player->gapless.start_time[stream_type] = 0;
1061 case GST_EVENT_SEGMENT:
1066 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1067 gst_event_copy_segment(event, &segment);
1069 if (segment.format != GST_FORMAT_TIME)
1072 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1073 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1074 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1075 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1076 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1077 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1079 /* keep the all the segment ev to cover the seeking */
1080 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1081 player->gapless.update_segment[stream_type] = TRUE;
1083 if (!player->gapless.running)
1086 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1088 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1090 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1091 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1092 gst_event_unref(event);
1093 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1099 gdouble proportion = 0.0;
1100 GstClockTimeDiff diff = 0;
1101 GstClockTime timestamp = 0;
1102 gint64 running_time_diff = -1;
1103 GstQOSType type = 0;
1104 GstEvent *tmpev = NULL;
1106 running_time_diff = player->gapless.segment[stream_type].base;
1108 if (running_time_diff <= 0) /* don't need to adjust */
1111 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1112 gst_event_unref(event);
1114 if (timestamp < running_time_diff) {
1115 LOGW("QOS event from previous group");
1116 ret = GST_PAD_PROBE_DROP;
1121 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1122 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1123 stream_type, GST_TIME_ARGS(timestamp),
1124 GST_TIME_ARGS(running_time_diff),
1125 GST_TIME_ARGS(timestamp - running_time_diff));
1128 timestamp -= running_time_diff;
1130 /* That case is invalid for QoS events */
1131 if (diff < 0 && -diff > timestamp) {
1132 LOGW("QOS event from previous group");
1133 ret = GST_PAD_PROBE_DROP;
1137 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1138 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1148 gst_caps_unref(caps);
1152 /* create fakesink for audio or video path without audiobin or videobin */
1154 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1156 GstElement *pipeline = NULL;
1157 GstElement *fakesink = NULL;
1158 GstPad *sinkpad = NULL;
1161 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1163 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1166 fakesink = gst_element_factory_make("fakesink", NULL);
1167 if (fakesink == NULL) {
1168 LOGE("failed to create fakesink");
1172 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1173 LOGE("failed to add fakesink to pipeline");
1178 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1180 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1182 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1183 LOGE("failed to link fakesink");
1187 if (strstr(name, "video")) {
1188 if (player->v_stream_caps) {
1189 gst_caps_unref(player->v_stream_caps);
1190 player->v_stream_caps = NULL;
1192 if (player->ini.set_dump_element_flag)
1193 __mmplayer_add_dump_buffer_probe(player, fakesink);
1196 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1197 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1199 /* store it as it's sink element */
1200 __mmplayer_add_sink(player, fakesink, FALSE);
1203 gst_object_unref(GST_OBJECT(sinkpad));
1211 gst_object_unref(GST_OBJECT(sinkpad));
1214 gst_element_set_state(fakesink, GST_STATE_NULL);
1216 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1217 gst_object_unref(GST_OBJECT(fakesink));
1224 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1226 GstElement *pipeline = NULL;
1227 g_autoptr(GstElement) concat = NULL;
1228 g_autoptr(GstPad) srcpad = NULL;
1231 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1233 concat = gst_element_factory_make("concat", NULL);
1235 LOGE("failed to create concat");
1239 srcpad = gst_element_get_static_pad(concat, "src");
1241 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1242 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1243 __mmplayer_gst_combiner_blocked, NULL, NULL);
1244 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1245 __mmplayer_gst_combiner_event_probe, player, NULL);
1248 gst_element_set_state(concat, GST_STATE_PAUSED);
1250 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1251 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1252 LOGE("failed to add concat to pipeline");
1253 gst_element_set_state(concat, GST_STATE_NULL);
1257 LOGD("Create concat [%d] element", elem_idx);
1259 player->pipeline->mainbin[elem_idx].id = elem_idx;
1260 player->pipeline->mainbin[elem_idx].gst = concat;
1263 return g_steal_pointer(&concat);
1267 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1269 GstElement *pipeline = NULL;
1270 GstElement *selector = NULL;
1271 GstPad *srcpad = NULL;
1274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1276 selector = gst_element_factory_make("input-selector", NULL);
1278 LOGE("failed to create input-selector");
1281 g_object_set(selector, "sync-streams", TRUE, NULL);
1283 srcpad = gst_element_get_static_pad(selector, "src");
1285 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1286 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1287 __mmplayer_gst_combiner_blocked, NULL, NULL);
1288 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1289 __mmplayer_gst_combiner_event_probe, player, NULL);
1291 gst_element_set_state(selector, GST_STATE_PAUSED);
1293 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1294 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1295 LOGE("failed to add selector to pipeline");
1297 if (player->track[stream_type].block_id != 0)
1298 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1299 player->track[stream_type].block_id = 0;
1301 if (player->track[stream_type].event_probe_id != 0)
1302 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1303 player->track[stream_type].event_probe_id = 0;
1305 gst_object_unref(GST_OBJECT(srcpad));
1307 gst_element_set_state(selector, GST_STATE_NULL);
1308 gst_object_unref(GST_OBJECT(selector));
1312 gst_object_unref(GST_OBJECT(srcpad));
1314 player->pipeline->mainbin[elem_idx].id = elem_idx;
1315 player->pipeline->mainbin[elem_idx].gst = selector;
1322 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1324 mmplayer_t *player = (mmplayer_t *)data;
1325 GstElement *combiner = NULL;
1326 GstCaps *caps = NULL;
1327 GstStructure *str = NULL;
1328 const gchar *name = NULL;
1329 GstPad *sinkpad = NULL;
1330 gboolean first_track = FALSE;
1331 gboolean caps_ret = TRUE;
1333 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1334 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1337 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1338 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1340 LOGD("pad-added signal handling");
1342 /* get mimetype from caps */
1343 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1347 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1349 LOGD("detected mimetype : %s", name);
1352 if (strstr(name, "video")) {
1354 gchar *caps_str = NULL;
1356 caps_str = gst_caps_to_string(caps);
1357 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1358 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1359 player->set_mode.video_zc = true;
1361 MMPLAYER_FREEIF(caps_str);
1363 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1364 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1366 LOGD("surface type : %d", stype);
1368 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1369 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1373 /* in case of exporting video frame, it requires the 360 video filter.
1374 * it will be handled in _no_more_pads(). */
1375 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1376 __mmplayer_gst_make_fakesink(player, pad, name);
1380 if (MMPLAYER_USE_DECODEBIN(player)) {
1381 LOGD("video selector is required");
1382 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1384 LOGD("video concat is required");
1385 elem_idx = MMPLAYER_M_V_CONCAT;
1387 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1388 } else if (strstr(name, "audio")) {
1389 gint samplerate = 0;
1392 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1393 if (player->build_audio_offload)
1394 player->no_more_pad = TRUE; /* remove state holder */
1395 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1399 gst_structure_get_int(str, "rate", &samplerate);
1400 gst_structure_get_int(str, "channels", &channels);
1402 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1403 __mmplayer_gst_make_fakesink(player, pad, name);
1406 if (MMPLAYER_USE_DECODEBIN(player)) {
1407 LOGD("audio selector is required");
1408 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1410 LOGD("audio concat is required");
1411 elem_idx = MMPLAYER_M_A_CONCAT;
1413 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1415 } else if (strstr(name, "text")) {
1416 if (MMPLAYER_USE_DECODEBIN(player)) {
1417 LOGD("text selector is required");
1418 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1420 LOGD("text concat is required");
1421 elem_idx = MMPLAYER_M_T_CONCAT;
1423 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1425 LOGE("invalid caps info");
1429 /* check selector and create it */
1430 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1431 if (MMPLAYER_USE_DECODEBIN(player))
1432 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1434 combiner = __mmplayer_gst_make_concat(player, elem_idx, stream_type);
1440 LOGD("Combiner element is already created.");
1444 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1446 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1448 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1449 LOGE("failed to link combiner");
1450 gst_object_unref(GST_OBJECT(combiner));
1455 if (MMPLAYER_USE_DECODEBIN(player)) {
1456 LOGD("this track will be activated");
1457 g_object_set(combiner, "active-pad", sinkpad, NULL);
1461 if (MMPLAYER_USE_DECODEBIN(player)) {
1462 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1464 /* apply the text track information */
1465 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1466 mm_player_set_attribute((MMHandleType)player, NULL,
1467 "content_text_track_num", player->track[stream_type].total_track_num,
1468 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1469 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1476 gst_caps_unref(caps);
1479 gst_object_unref(GST_OBJECT(sinkpad));
1483 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1488 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1490 GstPad *srcpad = NULL;
1493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1495 LOGD("type %d", type);
1498 LOGD("there is no %d track", type);
1502 srcpad = gst_element_get_static_pad(combiner, "src");
1504 LOGE("failed to get srcpad from combiner");
1508 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1510 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1512 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1513 if (player->track[type].block_id) {
1514 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1515 player->track[type].block_id = 0;
1519 gst_object_unref(GST_OBJECT(srcpad));
1528 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1530 gint active_index = 0;
1533 MMPLAYER_RETURN_IF_FAIL(player);
1535 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1537 /* change track to active pad */
1538 active_index = player->track[type].active_track_index;
1539 if ((active_index != DEFAULT_TRACK_INDEX) &&
1540 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1541 LOGW("failed to change %d type track to %d", type, active_index);
1542 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1546 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1547 mm_player_set_attribute((MMHandleType)player, NULL,
1548 "content_text_track_num", player->track[type].total_track_num,
1549 "current_text_track_index", player->track[type].active_track_index, NULL);
1556 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1559 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1561 if (!audio_selector) {
1562 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1564 /* in case the source is changed, output can be changed. */
1565 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1566 LOGD("remove previous audiobin if it exist");
1568 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1569 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1571 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1572 MMPLAYER_FREEIF(player->pipeline->audiobin);
1575 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1576 _mmplayer_pipeline_complete(NULL, player);
1581 /* apply the audio track information */
1582 if (MMPLAYER_USE_DECODEBIN(player))
1583 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1585 /* create audio sink path */
1586 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1587 LOGE("failed to create audio sink path");
1596 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1599 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1601 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1602 LOGD("text path is not supported");
1606 /* apply the text track information */
1607 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1609 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1610 player->has_closed_caption = TRUE;
1612 /* create text decode path */
1613 player->no_more_pad = TRUE;
1615 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1616 LOGE("failed to create text sink path");
1625 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1627 gint64 dur_bytes = 0L;
1630 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1631 player->pipeline->mainbin && player->streamer, FALSE);
1633 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1634 LOGE("fail to get duration.");
1636 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1637 * use file information was already set on Q2 when it was created. */
1638 _mm_player_streaming_set_queue2(player->streamer,
1639 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1640 TRUE, /* use_buffering */
1641 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1642 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1649 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1651 mmplayer_t *player = NULL;
1652 GstElement *video_selector = NULL;
1653 GstElement *audio_selector = NULL;
1654 GstElement *text_selector = NULL;
1657 player = (mmplayer_t *)data;
1659 LOGD("no-more-pad signal handling");
1661 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1662 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1663 LOGW("player is shutting down");
1667 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1668 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1669 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1670 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1671 LOGE("failed to set queue2 buffering");
1676 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1677 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1678 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1680 if (!video_selector && !audio_selector && !text_selector) {
1681 LOGW("there is no selector");
1682 player->no_more_pad = TRUE;
1686 /* create video path followed by video-select */
1687 if (video_selector && !audio_selector && !text_selector)
1688 player->no_more_pad = TRUE;
1690 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1693 /* create audio path followed by audio-select */
1694 if (audio_selector && !text_selector)
1695 player->no_more_pad = TRUE;
1697 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1700 /* create text path followed by text-select */
1701 __mmplayer_create_text_sink_path(player, text_selector);
1704 _mmplayer_set_reconfigure_state(player, FALSE);
1709 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1711 gboolean ret = FALSE;
1712 GstElement *pipeline = NULL;
1713 GstPad *sinkpad = NULL;
1716 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1719 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1721 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1723 LOGE("failed to get pad from sinkbin");
1729 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1730 LOGE("failed to link sinkbin for reusing");
1731 goto EXIT; /* exit either pass or fail */
1735 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1736 LOGE("failed to set state(READY) to sinkbin");
1741 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1742 LOGE("failed to add sinkbin to pipeline");
1747 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1748 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1753 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1754 LOGE("failed to set state(PAUSED) to sinkbin");
1763 gst_object_unref(GST_OBJECT(sinkpad));
1771 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1773 mmplayer_t *player = NULL;
1774 GstCaps *caps = NULL;
1775 gchar *caps_str = NULL;
1776 GstStructure *str = NULL;
1777 const gchar *name = NULL;
1778 GstElement *sinkbin = NULL;
1779 gboolean reusing = FALSE;
1780 gboolean caps_ret = TRUE;
1781 gchar *sink_pad_name = "sink";
1784 player = (mmplayer_t *)data;
1787 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1788 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1789 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1791 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1795 gst_caps_unref(caps);
1796 caps = gst_caps_ref(ref_caps);
1799 caps_str = gst_caps_to_string(caps);
1801 LOGD("detected mimetype : %s", name);
1803 if (strstr(name, "audio")) {
1804 if (player->pipeline->audiobin == NULL) {
1805 const gchar *audio_format = gst_structure_get_string(str, "format");
1807 LOGD("original audio format %s", audio_format);
1808 mm_player_set_attribute((MMHandleType)player, NULL,
1809 "content_audio_format", audio_format, strlen(audio_format), NULL);
1812 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1813 LOGE("failed to create audiobin. continuing without audio");
1817 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1818 LOGD("creating audiobin success");
1821 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1822 LOGD("reusing audiobin");
1823 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1825 } else if (strstr(name, "video")) {
1826 /* 1. zero copy is updated at _decode_pad_added()
1827 * 2. NULL surface type is handled in _decode_pad_added() */
1828 LOGD("zero copy %d", player->set_mode.video_zc);
1829 if (player->pipeline->videobin == NULL) {
1830 int surface_type = 0;
1831 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1832 LOGD("display_surface_type (%d)", surface_type);
1834 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1835 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1836 LOGE("failed to acquire video overlay resource");
1840 player->interrupted_by_resource = FALSE;
1842 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1843 LOGE("failed to create videobin. continuing without video");
1847 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1848 LOGD("creating videosink bin success");
1851 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1852 LOGD("re-using videobin");
1853 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1855 } else if (strstr(name, "text")) {
1856 if (player->pipeline->textbin == NULL) {
1857 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1858 LOGE("failed to create text sink bin. continuing without text");
1862 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1863 player->textsink_linked = 1;
1864 LOGD("creating textsink bin success");
1866 if (!player->textsink_linked) {
1867 LOGD("re-using textbin");
1869 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1870 player->textsink_linked = 1;
1872 /* linked textbin exist which means that the external subtitle path exist already */
1873 LOGW("ignoring internal subtitle since external subtitle is available");
1876 sink_pad_name = "text_sink";
1878 LOGW("unknown mime type %s, ignoring it", name);
1882 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1885 LOGD("[handle: %p] success to create and link sink bin", player);
1887 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1888 * streaming task. if the task blocked, then buffer will not flow to the next element
1889 *(autoplugging element). so this is special hack for streaming. please try to remove it
1891 /* dec stream count. we can remove fakesink if it's zero */
1892 if (player->num_dynamic_pad)
1893 player->num_dynamic_pad--;
1895 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1897 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1898 _mmplayer_pipeline_complete(NULL, player);
1902 MMPLAYER_FREEIF(caps_str);
1905 gst_caps_unref(caps);
1911 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1913 int required_angle = 0; /* Angle required for straight view */
1914 int rotation_angle = 0;
1916 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1917 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1919 /* Counter clockwise */
1920 switch (orientation) {
1925 required_angle = 270;
1928 required_angle = 180;
1931 required_angle = 90;
1935 rotation_angle = display_angle + required_angle;
1936 if (rotation_angle >= 360)
1937 rotation_angle -= 360;
1939 /* check if supported or not */
1940 if (rotation_angle % 90) {
1941 LOGD("not supported rotation angle = %d", rotation_angle);
1945 switch (rotation_angle) {
1947 *value = MM_DISPLAY_ROTATION_NONE;
1950 *value = MM_DISPLAY_ROTATION_90;
1953 *value = MM_DISPLAY_ROTATION_180;
1956 *value = MM_DISPLAY_ROTATION_270;
1960 LOGD("setting rotation property value : %d", *value);
1966 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1968 int display_rotation = 0;
1969 gchar *org_orient = NULL;
1970 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1973 LOGE("cannot get content attribute");
1974 return MM_ERROR_PLAYER_INTERNAL;
1977 if (display_angle) {
1978 /* update user rotation */
1979 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1981 /* Counter clockwise */
1982 switch (display_rotation) {
1983 case MM_DISPLAY_ROTATION_NONE:
1986 case MM_DISPLAY_ROTATION_90:
1987 *display_angle = 90;
1989 case MM_DISPLAY_ROTATION_180:
1990 *display_angle = 180;
1992 case MM_DISPLAY_ROTATION_270:
1993 *display_angle = 270;
1996 LOGW("wrong angle type : %d", display_rotation);
1999 LOGD("check user angle: %d", *display_angle);
2003 /* Counter clockwise */
2004 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2007 if (!strcmp(org_orient, "rotate-90"))
2009 else if (!strcmp(org_orient, "rotate-180"))
2011 else if (!strcmp(org_orient, "rotate-270"))
2014 LOGD("original rotation is %s", org_orient);
2016 LOGD("content_video_orientation get fail");
2019 LOGD("check orientation: %d", *orientation);
2022 return MM_ERROR_NONE;
2025 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2027 int rotation_value = 0;
2028 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2029 int display_angle = 0;
2032 /* check video sinkbin is created */
2033 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2036 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2038 /* get rotation value to set */
2039 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2040 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2041 LOGD("set video param : rotate %d", rotation_value);
2044 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2046 MMHandleType attrs = 0;
2050 /* check video sinkbin is created */
2051 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2052 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2055 attrs = MMPLAYER_GET_ATTRS(player);
2056 MMPLAYER_RETURN_IF_FAIL(attrs);
2058 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2059 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2060 LOGD("set video param : visible %d", visible);
2063 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2065 MMHandleType attrs = 0;
2066 int display_method = 0;
2069 /* check video sinkbin is created */
2070 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2073 attrs = MMPLAYER_GET_ATTRS(player);
2074 MMPLAYER_RETURN_IF_FAIL(attrs);
2076 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2077 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2078 LOGD("set video param : method %d", display_method);
2081 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2083 MMHandleType attrs = 0;
2087 /* check video sinkbin is created */
2088 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2091 attrs = MMPLAYER_GET_ATTRS(player);
2092 MMPLAYER_RETURN_IF_FAIL(attrs);
2094 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2095 MMPLAYER_RETURN_IF_FAIL(handle);
2097 gst_video_overlay_set_video_roi_area(
2098 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2099 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2100 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2101 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2104 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2106 MMHandleType attrs = 0;
2111 int win_roi_width = 0;
2112 int win_roi_height = 0;
2115 /* check video sinkbin is created */
2116 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2119 attrs = MMPLAYER_GET_ATTRS(player);
2120 MMPLAYER_RETURN_IF_FAIL(attrs);
2122 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2123 MMPLAYER_RETURN_IF_FAIL(handle);
2125 /* It should be set after setting window */
2126 mm_attrs_multiple_get(attrs, NULL,
2127 "display_win_roi_x", &win_roi_x,
2128 "display_win_roi_y", &win_roi_y,
2129 "display_win_roi_width", &win_roi_width,
2130 "display_win_roi_height", &win_roi_height, NULL);
2132 /* After setting window handle, set display roi area */
2133 gst_video_overlay_set_display_roi_area(
2134 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2135 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2136 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2137 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2140 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2142 MMHandleType attrs = 0;
2143 gchar *handle = NULL;
2145 /* check video sinkbin is created */
2146 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2149 attrs = MMPLAYER_GET_ATTRS(player);
2150 MMPLAYER_RETURN_IF_FAIL(attrs);
2152 /* common case if using overlay surface */
2153 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2154 MMPLAYER_RETURN_IF_FAIL(handle);
2156 gst_video_overlay_set_wl_window_exported_shell_handle(
2157 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2159 LOGD("set video param: exported_shell_handle (%s)", handle);
2162 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2164 MMHandleType attrs = 0;
2167 /* check video sinkbin is created */
2168 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2171 attrs = MMPLAYER_GET_ATTRS(player);
2172 MMPLAYER_RETURN_IF_FAIL(attrs);
2174 /* common case if using overlay surface */
2175 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2176 MMPLAYER_RETURN_IF_FAIL(handle);
2178 /* default is using wl_surface_id */
2179 LOGD("set video param : wl_surface_id %d", handle);
2180 gst_video_overlay_set_wl_window_wl_surface_id(
2181 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2186 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2188 gboolean update_all_param = FALSE;
2189 int curr_type = MM_DISPLAY_SURFACE_NUM;
2193 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2194 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2195 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2196 LOGW("videosink is not ready yet");
2197 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2200 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2202 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2203 LOGE("current type(%d) is wrong", curr_type);
2204 return MM_ERROR_PLAYER_INTERNAL;
2207 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2208 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2209 return MM_ERROR_PLAYER_INTERNAL;
2212 LOGD("param_name : %s", param_name);
2213 if (!g_strcmp0(param_name, "update_all_param"))
2214 update_all_param = TRUE;
2216 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2217 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2219 return MM_ERROR_NONE;
2221 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2222 __mmplayer_video_param_set_display_overlay(player);
2223 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2224 __mmplayer_video_param_set_display_method(player);
2225 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2226 __mmplayer_video_param_set_display_visible(player);
2227 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2228 __mmplayer_video_param_set_display_rotation(player);
2229 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2230 __mmplayer_video_param_set_roi_area(player);
2231 if (update_all_param)
2232 __mmplayer_video_param_set_video_roi_area(player);
2235 return MM_ERROR_NONE;
2238 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2240 gboolean disable_overlay = FALSE;
2243 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2244 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2245 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2247 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2248 LOGW("Display control is not supported");
2249 return MM_ERROR_PLAYER_INTERNAL;
2252 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2254 if (disable == (bool)disable_overlay) {
2255 LOGE("It's the same with current setting: (%d)", disable);
2256 return MM_ERROR_NONE;
2260 LOGE("disable overlay");
2261 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2263 /* release overlay resource */
2264 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2265 LOGE("failed to release overlay resource");
2266 return MM_ERROR_PLAYER_INTERNAL;
2269 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2270 LOGE("failed to acquire video overlay resource");
2271 return MM_ERROR_PLAYER_INTERNAL;
2273 player->interrupted_by_resource = FALSE;
2275 LOGD("enable overlay");
2276 __mmplayer_video_param_set_display_overlay(player);
2277 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2278 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2282 return MM_ERROR_NONE;
2286 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2288 int ret = MM_ERROR_NONE;
2289 mmplayer_t *player = (mmplayer_t *)hplayer;
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2294 if (MMPLAYER_USE_DECODEBIN(player)) {
2295 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2300 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2301 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2302 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2304 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2306 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2308 /* release decoder resource */
2309 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2310 LOGE("failed to release video decoder resources");
2311 return MM_ERROR_PLAYER_INTERNAL;
2313 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2315 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2319 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2326 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2328 GList *bucket = element_bucket;
2329 mmplayer_gst_element_t *element = NULL;
2330 mmplayer_gst_element_t *prv_element = NULL;
2331 GstElement *tee_element = NULL;
2332 gint successful_link_count = 0;
2336 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2338 prv_element = (mmplayer_gst_element_t *)bucket->data;
2339 bucket = bucket->next;
2341 for (; bucket; bucket = bucket->next) {
2342 element = (mmplayer_gst_element_t *)bucket->data;
2344 if (element && element->gst) {
2345 if (prv_element && prv_element->gst) {
2346 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2348 prv_element->gst = tee_element;
2350 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2351 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2352 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2356 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2357 LOGD("linking [%s] to [%s] success",
2358 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2359 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2360 successful_link_count++;
2361 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2362 LOGD("keep audio-tee element for next audio pipeline branch");
2363 tee_element = prv_element->gst;
2366 LOGD("linking [%s] to [%s] failed",
2367 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2368 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2374 prv_element = element;
2379 return successful_link_count;
2383 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2385 GList *bucket = element_bucket;
2386 mmplayer_gst_element_t *element = NULL;
2387 int successful_add_count = 0;
2391 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2392 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2394 for (; bucket; bucket = bucket->next) {
2395 element = (mmplayer_gst_element_t *)bucket->data;
2397 if (element && element->gst) {
2398 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2399 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2400 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2401 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2404 successful_add_count++;
2410 return successful_add_count;
2414 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2416 mmplayer_t *player = (mmplayer_t *)data;
2417 GstCaps *caps = NULL;
2418 GstStructure *str = NULL;
2420 gboolean caps_ret = TRUE;
2424 MMPLAYER_RETURN_IF_FAIL(pad);
2425 MMPLAYER_RETURN_IF_FAIL(unused);
2426 MMPLAYER_RETURN_IF_FAIL(data);
2428 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2432 LOGD("name = %s", name);
2434 if (strstr(name, "audio")) {
2435 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2437 if (player->audio_stream_changed_cb) {
2438 LOGE("call the audio stream changed cb");
2439 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2441 } else if (strstr(name, "video")) {
2442 if ((name = gst_structure_get_string(str, "format")))
2443 player->set_mode.video_zc = name[0] == 'S';
2445 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2446 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2448 LOGW("invalid caps info");
2453 gst_caps_unref(caps);
2461 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2466 MMPLAYER_RETURN_IF_FAIL(player);
2468 if (player->audio_stream_buff_list) {
2469 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2470 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2473 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2474 __mmplayer_audio_stream_send_data(player, tmp);
2476 MMPLAYER_FREEIF(tmp->pcm_data);
2477 MMPLAYER_FREEIF(tmp);
2480 g_list_free(player->audio_stream_buff_list);
2481 player->audio_stream_buff_list = NULL;
2488 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2490 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2493 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2495 audio_stream.bitrate = a_buffer->bitrate;
2496 audio_stream.channel = a_buffer->channel;
2497 audio_stream.channel_mask = a_buffer->channel_mask;
2498 audio_stream.data_size = a_buffer->data_size;
2499 audio_stream.data = a_buffer->pcm_data;
2500 audio_stream.pcm_format = a_buffer->pcm_format;
2502 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2504 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2510 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2512 mmplayer_t *player = (mmplayer_t *)data;
2513 const gchar *pcm_format = NULL;
2516 guint64 channel_mask = 0;
2517 void *a_data = NULL;
2519 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2520 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2524 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2526 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2527 a_data = mapinfo.data;
2528 a_size = mapinfo.size;
2530 GstCaps *caps = gst_pad_get_current_caps(pad);
2531 GstStructure *structure = gst_caps_get_structure(caps, 0);
2533 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2535 pcm_format = gst_structure_get_string(structure, "format");
2536 gst_structure_get_int(structure, "rate", &rate);
2537 gst_structure_get_int(structure, "channels", &channel);
2538 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2539 gst_caps_unref(GST_CAPS(caps));
2541 /* In case of the sync is false, use buffer list. *
2542 * The num of buffer list depends on the num of audio channels */
2543 if (player->audio_stream_buff_list) {
2544 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2545 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2547 if (channel_mask == tmp->channel_mask) {
2549 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2551 if (tmp->data_size + a_size < tmp->buff_size) {
2552 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2553 tmp->data_size += a_size;
2555 /* send data to client */
2556 __mmplayer_audio_stream_send_data(player, tmp);
2558 if (a_size > tmp->buff_size) {
2559 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2560 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2561 if (tmp->pcm_data == NULL) {
2562 LOGE("failed to realloc data.");
2565 tmp->buff_size = a_size;
2567 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2568 memcpy(tmp->pcm_data, a_data, a_size);
2569 tmp->data_size = a_size;
2574 LOGE("data is empty in list.");
2580 /* create new audio stream data for newly found audio channel */
2581 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2582 if (a_buffer == NULL) {
2583 LOGE("failed to alloc data.");
2586 a_buffer->bitrate = rate;
2587 a_buffer->channel = channel;
2588 a_buffer->channel_mask = channel_mask;
2589 a_buffer->data_size = a_size;
2590 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2592 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2593 /* If sync is FALSE, use buffer list to reduce the IPC. */
2594 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2595 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2596 if (a_buffer->pcm_data == NULL) {
2597 LOGE("failed to alloc data.");
2598 MMPLAYER_FREEIF(a_buffer);
2601 memcpy(a_buffer->pcm_data, a_data, a_size);
2603 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2605 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2607 /* If sync is TRUE, send data directly. */
2608 a_buffer->pcm_data = a_data;
2609 __mmplayer_audio_stream_send_data(player, a_buffer);
2610 MMPLAYER_FREEIF(a_buffer);
2614 gst_buffer_unmap(buffer, &mapinfo);
2619 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2621 mmplayer_t *player = (mmplayer_t *)data;
2622 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2623 GstPad *sinkpad = NULL;
2624 GstElement *queue = NULL, *sink = NULL;
2627 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2629 queue = gst_element_factory_make("queue", NULL);
2630 if (queue == NULL) {
2631 LOGD("fail make queue");
2635 sink = gst_element_factory_make("fakesink", NULL);
2637 LOGD("fail make fakesink");
2641 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2643 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2644 LOGW("failed to link queue & sink");
2648 sinkpad = gst_element_get_static_pad(queue, "sink");
2650 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2651 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2655 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2657 gst_object_unref(sinkpad);
2658 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2659 g_object_set(sink, "sync", TRUE, NULL);
2660 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2662 /* keep the first sink reference only */
2663 if (!audiobin[MMPLAYER_A_SINK].gst) {
2664 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2665 audiobin[MMPLAYER_A_SINK].gst = sink;
2669 _mmplayer_add_signal_connection(player,
2671 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2673 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2676 __mmplayer_add_sink(player, sink, FALSE);
2678 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2679 LOGE("failed to sync state");
2683 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2684 LOGE("failed to sync state");
2692 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2694 gst_object_unref(GST_OBJECT(queue));
2698 gst_object_unref(GST_OBJECT(sink));
2702 gst_object_unref(GST_OBJECT(sinkpad));
2710 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2712 mmplayer_t *player = (mmplayer_t *)data;
2715 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2717 player->no_more_pad = TRUE;
2718 _mmplayer_pipeline_complete(NULL, player);
2725 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2727 #define MAX_PROPS_LEN 128
2728 mmplayer_gst_element_t *audiobin = NULL;
2729 gint latency_mode = 0;
2730 gchar *stream_type = NULL;
2731 gchar *latency = NULL;
2733 gchar stream_props[MAX_PROPS_LEN] = {0,};
2734 GstStructure *props = NULL;
2737 * It should be set after player creation through attribute.
2738 * But, it can not be changed during playing.
2741 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2743 audiobin = player->pipeline->audiobin;
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2746 if (player->sound.mute) {
2747 LOGD("mute enabled");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2751 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2752 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2755 snprintf(stream_props, sizeof(stream_props) - 1,
2756 "props,application.process.id.origin=%d", player->client_pid);
2758 snprintf(stream_props, sizeof(stream_props) - 1,
2759 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2760 stream_type, stream_id, player->client_pid);
2762 props = gst_structure_from_string(stream_props, NULL);
2763 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2764 LOGI("props result[%s].", stream_props);
2765 gst_structure_free(props);
2767 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2769 switch (latency_mode) {
2770 case AUDIO_LATENCY_MODE_LOW:
2771 latency = g_strdup("low");
2773 case AUDIO_LATENCY_MODE_MID:
2774 latency = g_strdup("mid");
2776 case AUDIO_LATENCY_MODE_HIGH:
2777 latency = g_strdup("high");
2780 latency = g_strdup("mid");
2784 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2786 LOGD("audiosink property - latency=%s", latency);
2788 MMPLAYER_FREEIF(latency);
2794 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2796 mmplayer_gst_element_t *audiobin = NULL;
2799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2800 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2802 audiobin = player->pipeline->audiobin;
2804 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2805 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2806 LOGE("failed to create media stream info");
2807 return MM_ERROR_PLAYER_INTERNAL;
2810 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2812 if (player->video360_yaw_radians <= M_PI &&
2813 player->video360_yaw_radians >= -M_PI &&
2814 player->video360_pitch_radians <= M_PI_2 &&
2815 player->video360_pitch_radians >= -M_PI_2) {
2816 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2817 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2818 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2819 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2820 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2821 "source-orientation-y", player->video360_metadata.init_view_heading,
2822 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2826 return MM_ERROR_NONE;
2830 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2832 mmplayer_gst_element_t *audiobin = NULL;
2833 GstPad *sink_pad = NULL;
2834 GstCaps *acaps = NULL;
2836 int pitch_control = 0;
2837 double pitch_value = 1.0;
2840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2841 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2843 audiobin = player->pipeline->audiobin;
2845 LOGD("make element for normal audio playback");
2847 /* audio bin structure for playback. {} means optional.
2848 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2850 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2851 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2854 /* for pitch control */
2855 mm_attrs_multiple_get(player->attrs, NULL,
2856 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2857 MM_PLAYER_PITCH_VALUE, &pitch_value,
2860 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2861 if (pitch_control && (player->videodec_linked == 0)) {
2862 GstElementFactory *factory;
2864 factory = gst_element_factory_find("pitch");
2866 gst_object_unref(factory);
2869 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2872 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2875 LOGW("there is no pitch element");
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2882 /* replaygain volume */
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2884 if (player->sound.rg_enable)
2885 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2887 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2890 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2892 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2893 /* currently, only openalsink uses volume element */
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2895 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2897 if (player->sound.mute) {
2898 LOGD("mute enabled");
2899 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2903 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2905 /* audio effect element. if audio effect is enabled */
2906 if ((strcmp(player->ini.audioeffect_element, ""))
2908 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2909 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2911 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2913 if ((!player->bypass_audio_effect)
2914 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2915 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2916 if (!_mmplayer_audio_effect_custom_apply(player))
2917 LOGI("apply audio effect(custom) setting success");
2921 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2922 && (player->set_mode.rich_audio)) {
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2927 /* create audio sink */
2928 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2929 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2930 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2932 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2933 if (player->is_360_feature_enabled &&
2934 player->is_content_spherical &&
2936 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2937 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2938 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2940 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2942 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2945 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2946 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2947 gst_caps_unref(acaps);
2949 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2951 player->is_openal_plugin_used = TRUE;
2953 if (player->is_360_feature_enabled && player->is_content_spherical)
2954 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2955 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2958 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2959 (player->videodec_linked && player->ini.use_system_clock)) {
2960 LOGD("system clock will be used.");
2961 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2964 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2965 __mmplayer_gst_set_pulsesink_property(player);
2966 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2967 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2972 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2973 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2975 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2976 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2977 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2978 gst_object_unref(GST_OBJECT(sink_pad));
2980 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2983 return MM_ERROR_NONE;
2985 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2987 return MM_ERROR_PLAYER_INTERNAL;
2991 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2993 mmplayer_gst_element_t *audiobin = NULL;
2994 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2996 gchar *dst_format = NULL;
2998 int dst_samplerate = 0;
2999 int dst_channels = 0;
3000 GstCaps *caps = NULL;
3001 char *caps_str = NULL;
3004 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3005 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3007 audiobin = player->pipeline->audiobin;
3009 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
3011 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
3013 [case 1] extract interleave audio pcm without playback
3014 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
3015 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
3017 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
3019 [case 2] deinterleave for each channel without playback
3020 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
3021 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
3023 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
3024 - fakesink (sync or not)
3027 [case 3] [case 1(sync only)] + playback
3028 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3030 * src - ... - tee - queue1 - playback path
3031 - queue2 - [case1 pipeline with sync]
3033 [case 4] [case 2(sync only)] + playback
3034 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3036 * src - ... - tee - queue1 - playback path
3037 - queue2 - [case2 pipeline with sync]
3041 /* 1. create tee and playback path
3042 'tee' should be added at first to copy the decoded stream
3044 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3045 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3046 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3048 /* tee - path 1 : for playback path */
3049 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3050 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3052 /* tee - path 2 : for extract path */
3053 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3054 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3057 /* if there is tee, 'tee - path 2' is linked here */
3059 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3062 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3064 /* 2. decide the extract pcm format */
3065 mm_attrs_multiple_get(player->attrs, NULL,
3066 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3067 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3068 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3071 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3072 dst_format, dst_len, dst_samplerate, dst_channels);
3074 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3075 mm_attrs_multiple_get(player->attrs, NULL,
3076 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3077 "content_audio_samplerate", &dst_samplerate,
3078 "content_audio_channels", &dst_channels,
3081 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3082 dst_format, dst_len, dst_samplerate, dst_channels);
3084 /* If there is no enough information, set it to platform default value. */
3085 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3086 LOGD("set platform default format");
3087 dst_format = DEFAULT_PCM_OUT_FORMAT;
3089 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3090 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3093 /* 3. create capsfilter */
3094 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3095 caps = gst_caps_new_simple("audio/x-raw",
3096 "format", G_TYPE_STRING, dst_format,
3097 "rate", G_TYPE_INT, dst_samplerate,
3098 "channels", G_TYPE_INT, dst_channels,
3101 caps_str = gst_caps_to_string(caps);
3102 LOGD("new caps : %s", caps_str);
3104 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3107 gst_caps_unref(caps);
3108 MMPLAYER_FREEIF(caps_str);
3110 /* 4-1. create deinterleave to extract pcm for each channel */
3111 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3112 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3113 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3115 /* audiosink will be added after getting signal for each channel */
3116 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3117 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3118 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3119 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3120 player->no_more_pad = FALSE;
3122 /* 4-2. create fakesink to extract interleaved pcm */
3123 LOGD("add audio fakesink for interleaved audio");
3124 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3125 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3126 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3127 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3129 _mmplayer_add_signal_connection(player,
3130 G_OBJECT(audiobin[extract_sink_id].gst),
3131 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3133 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3136 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3140 return MM_ERROR_NONE;
3142 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3144 return MM_ERROR_PLAYER_INTERNAL;
3148 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3150 int ret = MM_ERROR_NONE;
3151 mmplayer_gst_element_t *audiobin = NULL;
3152 GList *element_bucket = NULL;
3155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3156 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3158 audiobin = player->pipeline->audiobin;
3160 if (player->build_audio_offload) { /* skip all the audio filters */
3161 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3163 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3164 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3165 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3167 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3171 /* FIXME: need to mention the supportable condition at API reference */
3172 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3173 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3175 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3177 if (ret != MM_ERROR_NONE)
3180 LOGD("success to make audio bin element");
3181 *bucket = element_bucket;
3184 return MM_ERROR_NONE;
3187 LOGE("failed to make audio bin element");
3188 g_list_free(element_bucket);
3192 return MM_ERROR_PLAYER_INTERNAL;
3196 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3198 mmplayer_gst_element_t *first_element = NULL;
3199 mmplayer_gst_element_t *audiobin = NULL;
3201 GstPad *ghostpad = NULL;
3202 GList *element_bucket = NULL;
3206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3209 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3211 LOGE("failed to allocate memory for audiobin");
3212 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3216 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3217 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3218 if (!audiobin[MMPLAYER_A_BIN].gst) {
3219 LOGE("failed to create audiobin");
3224 player->pipeline->audiobin = audiobin;
3226 /* create audio filters and audiosink */
3227 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3230 /* adding created elements to bin */
3231 LOGD("adding created elements to bin");
3232 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3235 /* linking elements in the bucket by added order. */
3236 LOGD("Linking elements in the bucket by added order.");
3237 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3240 /* get first element's sinkpad for creating ghostpad */
3241 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3242 if (!first_element) {
3243 LOGE("failed to get first elem");
3247 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3249 LOGE("failed to get pad from first element of audiobin");
3253 ghostpad = gst_ghost_pad_new("sink", pad);
3255 LOGE("failed to create ghostpad");
3259 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3260 LOGE("failed to add ghostpad to audiobin");
3264 gst_object_unref(pad);
3266 g_list_free(element_bucket);
3269 return MM_ERROR_NONE;
3272 LOGD("ERROR : releasing audiobin");
3275 gst_object_unref(GST_OBJECT(pad));
3278 gst_object_unref(GST_OBJECT(ghostpad));
3281 g_list_free(element_bucket);
3283 /* release element which are not added to bin */
3284 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3285 /* NOTE : skip bin */
3286 if (audiobin[i].gst) {
3287 GstObject *parent = NULL;
3288 parent = gst_element_get_parent(audiobin[i].gst);
3291 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3292 audiobin[i].gst = NULL;
3294 gst_object_unref(GST_OBJECT(parent));
3298 /* release audiobin with it's children */
3299 if (audiobin[MMPLAYER_A_BIN].gst)
3300 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3302 MMPLAYER_FREEIF(audiobin);
3304 player->pipeline->audiobin = NULL;
3306 return MM_ERROR_PLAYER_INTERNAL;
3310 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3312 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3316 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3318 int ret = MM_ERROR_NONE;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3321 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3323 MMPLAYER_VIDEO_BO_LOCK(player);
3325 if (player->video_bo_list) {
3326 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3327 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3328 if (tmp && tmp->bo == bo) {
3330 LOGD("release bo %p", bo);
3331 tbm_bo_unref(tmp->bo);
3332 MMPLAYER_VIDEO_BO_UNLOCK(player);
3333 MMPLAYER_VIDEO_BO_SIGNAL(player);
3338 /* hw codec is running or the list was reset for DRC. */
3339 LOGW("there is no bo list.");
3341 MMPLAYER_VIDEO_BO_UNLOCK(player);
3343 LOGW("failed to find bo %p", bo);
3347 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3353 tbm_bo_unref(tmp->bo);
3358 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3361 MMPLAYER_RETURN_IF_FAIL(player);
3363 MMPLAYER_VIDEO_BO_LOCK(player);
3364 if (player->video_bo_list) {
3365 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3366 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3367 player->video_bo_list = NULL;
3369 player->video_bo_size = 0;
3370 MMPLAYER_VIDEO_BO_UNLOCK(player);
3377 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3380 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3381 gboolean ret = TRUE;
3382 gint64 end_time = 0;
3384 /* check DRC, if it is, destroy the prev bo list to create again */
3385 if (player->video_bo_size != size) {
3386 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3387 __mmplayer_video_stream_destroy_bo_list(player);
3388 player->video_bo_size = size;
3391 MMPLAYER_VIDEO_BO_LOCK(player);
3393 if ((!player->video_bo_list) ||
3394 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3396 /* create bo list */
3398 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3400 if (player->video_bo_list) {
3401 /* if bo list did not created all, try it again. */
3402 idx = g_list_length(player->video_bo_list);
3403 LOGD("bo list exist(len: %d)", idx);
3406 for (; idx < player->ini.num_of_video_bo; idx++) {
3407 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3409 LOGE("Fail to alloc bo_info.");
3412 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3414 LOGE("Fail to tbm_bo_alloc.");
3415 MMPLAYER_FREEIF(bo_info);
3418 bo_info->used = FALSE;
3419 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3422 /* update video num buffers */
3423 LOGD("video_num_buffers : %d", idx);
3424 mm_player_set_attribute((MMHandleType)player, NULL,
3425 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3426 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3430 MMPLAYER_VIDEO_BO_UNLOCK(player);
3435 if (player->ini.video_bo_timeout > 0)
3436 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3439 /* get bo from list*/
3440 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3441 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3442 if (tmp && (tmp->used == FALSE)) {
3443 LOGD("found bo %p to use", tmp->bo);
3445 MMPLAYER_VIDEO_BO_UNLOCK(player);
3446 return tbm_bo_ref(tmp->bo);
3450 if (player->ini.video_bo_timeout <= 0) {
3451 MMPLAYER_VIDEO_BO_WAIT(player);
3453 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3455 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3461 MMPLAYER_VIDEO_BO_UNLOCK(player);
3466 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3468 mmplayer_t *player = (mmplayer_t *)data;
3470 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3472 /* send prerolled pkt */
3473 player->video_stream_prerolled = false;
3475 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3477 /* not to send prerolled pkt again */
3478 player->video_stream_prerolled = true;
3482 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3484 mmplayer_t *player = (mmplayer_t *)data;
3485 mmplayer_video_decoded_data_info_t *stream = NULL;
3486 GstMemory *mem = NULL;
3489 MMPLAYER_RETURN_IF_FAIL(player);
3490 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3492 if (player->video_stream_prerolled) {
3493 player->video_stream_prerolled = false;
3494 LOGD("skip the prerolled pkt not to send it again");
3498 /* clear stream data structure */
3499 stream = __mmplayer_create_stream_from_pad(pad);
3501 LOGE("failed to alloc stream");
3505 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3507 /* set size and timestamp */
3508 mem = gst_buffer_peek_memory(buffer, 0);
3509 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3510 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3512 /* check zero-copy */
3513 if (player->set_mode.video_zc &&
3514 player->set_mode.video_export &&
3515 gst_is_tizen_memory(mem)) {
3516 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3517 stream->internal_buffer = gst_buffer_ref(buffer);
3518 } else { /* sw codec */
3519 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3522 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3526 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3527 LOGE("failed to send video decoded data.");
3534 LOGE("release video stream resource.");
3535 if (gst_is_tizen_memory(mem)) {
3537 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3539 tbm_bo_unref(stream->bo[i]);
3542 /* unref gst buffer */
3543 if (stream->internal_buffer)
3544 gst_buffer_unref(stream->internal_buffer);
3547 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3549 MMPLAYER_FREEIF(stream);
3554 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3556 mmplayer_gst_element_t *videobin = NULL;
3559 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3561 videobin = player->pipeline->videobin;
3563 /* Set spatial media metadata and/or user settings to the element.
3565 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3566 "projection-type", player->video360_metadata.projection_type, NULL);
3568 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3569 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3571 if (player->video360_metadata.full_pano_width_pixels &&
3572 player->video360_metadata.full_pano_height_pixels &&
3573 player->video360_metadata.cropped_area_image_width &&
3574 player->video360_metadata.cropped_area_image_height) {
3575 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3576 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3577 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3578 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3579 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3580 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3581 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3585 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3586 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3587 "horizontal-fov", player->video360_horizontal_fov,
3588 "vertical-fov", player->video360_vertical_fov, NULL);
3591 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3592 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3593 "zoom", 1.0f / player->video360_zoom, NULL);
3596 if (player->video360_yaw_radians <= M_PI &&
3597 player->video360_yaw_radians >= -M_PI &&
3598 player->video360_pitch_radians <= M_PI_2 &&
3599 player->video360_pitch_radians >= -M_PI_2) {
3600 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3601 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3602 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3603 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3604 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3605 "pose-yaw", player->video360_metadata.init_view_heading,
3606 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3609 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3610 "passthrough", !player->is_video360_enabled, NULL);
3617 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3619 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3620 GList *element_bucket = NULL;
3623 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3625 /* create video360 filter */
3626 if (player->is_360_feature_enabled && player->is_content_spherical) {
3627 LOGD("create video360 element");
3628 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3629 __mmplayer_gst_set_video360_property(player);
3633 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3634 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3635 player->set_mode.video_zc) {
3636 LOGD("skip creating the videoconv and rotator");
3637 return MM_ERROR_NONE;
3640 /* in case of sw codec & overlay surface type, except 360 playback.
3641 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3642 LOGD("create video converter: %s", video_csc);
3643 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3646 *bucket = element_bucket;
3648 return MM_ERROR_NONE;
3650 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3651 g_list_free(element_bucket);
3655 return MM_ERROR_PLAYER_INTERNAL;
3659 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3661 gchar *factory_name = NULL;
3663 switch (surface_type) {
3664 case MM_DISPLAY_SURFACE_OVERLAY:
3666 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3667 if (strlen(player->ini.videosink_element_overlay) > 0)
3668 factory_name = player->ini.videosink_element_overlay;
3670 case MM_DISPLAY_SURFACE_REMOTE:
3672 case MM_DISPLAY_SURFACE_NULL:
3673 if (strlen(player->ini.videosink_element_fake) > 0)
3674 factory_name = player->ini.videosink_element_fake;
3677 LOGE("unidentified surface type");
3681 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3682 return factory_name;
3686 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3688 gchar *factory_name = NULL;
3689 mmplayer_gst_element_t *videobin = NULL;
3694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3696 videobin = player->pipeline->videobin;
3697 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3699 attrs = MMPLAYER_GET_ATTRS(player);
3701 LOGE("cannot get content attribute");
3702 return MM_ERROR_PLAYER_INTERNAL;
3705 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3706 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3707 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3708 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3709 "use-tbm", use_tbm, NULL);
3712 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3713 return MM_ERROR_PLAYER_INTERNAL;
3715 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3718 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3719 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3722 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3724 LOGD("disable last-sample");
3725 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3728 if (player->set_mode.video_export) {
3730 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3731 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3732 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3734 _mmplayer_add_signal_connection(player,
3735 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3736 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3738 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3741 _mmplayer_add_signal_connection(player,
3742 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3743 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3745 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3749 if (videobin[MMPLAYER_V_SINK].gst) {
3750 GstPad *sink_pad = NULL;
3751 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3753 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3754 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3755 gst_object_unref(GST_OBJECT(sink_pad));
3757 LOGE("failed to get sink pad from videosink");
3761 return MM_ERROR_NONE;
3766 * - video overlay surface(arm/x86) : tizenwlsink
3769 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3772 GList *element_bucket = NULL;
3773 mmplayer_gst_element_t *first_element = NULL;
3774 mmplayer_gst_element_t *videobin = NULL;
3775 gchar *videosink_factory_name = NULL;
3778 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3781 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3783 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3785 player->pipeline->videobin = videobin;
3788 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3789 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3790 if (!videobin[MMPLAYER_V_BIN].gst) {
3791 LOGE("failed to create videobin");
3795 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3798 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3799 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3801 /* additional setting for sink plug-in */
3802 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3803 LOGE("failed to set video property");
3807 /* store it as it's sink element */
3808 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3810 /* adding created elements to bin */
3811 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3812 LOGE("failed to add elements");
3816 /* Linking elements in the bucket by added order */
3817 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3818 LOGE("failed to link elements");
3822 /* get first element's sinkpad for creating ghostpad */
3823 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3824 if (!first_element) {
3825 LOGE("failed to get first element from bucket");
3829 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3831 LOGE("failed to get pad from first element");
3835 /* create ghostpad */
3836 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3837 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3838 LOGE("failed to add ghostpad to videobin");
3841 gst_object_unref(pad);
3843 /* done. free allocated variables */
3844 g_list_free(element_bucket);
3848 return MM_ERROR_NONE;
3851 LOGE("ERROR : releasing videobin");
3852 g_list_free(element_bucket);
3855 gst_object_unref(GST_OBJECT(pad));
3857 /* release videobin with it's children */
3858 if (videobin[MMPLAYER_V_BIN].gst)
3859 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3861 MMPLAYER_FREEIF(videobin);
3862 player->pipeline->videobin = NULL;
3864 return MM_ERROR_PLAYER_INTERNAL;
3868 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3870 GList *element_bucket = NULL;
3871 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3873 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3874 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3875 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3876 "signal-handoffs", FALSE,
3879 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3880 _mmplayer_add_signal_connection(player,
3881 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3882 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3884 G_CALLBACK(__mmplayer_update_subtitle),
3887 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3888 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3890 if (!player->play_subtitle) {
3891 LOGD("add textbin sink as sink element of whole pipeline.");
3892 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3895 /* adding created elements to bin */
3896 LOGD("adding created elements to bin");
3897 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3898 LOGE("failed to add elements");
3902 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3903 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3904 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3906 /* linking elements in the bucket by added order. */
3907 LOGD("Linking elements in the bucket by added order.");
3908 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3909 LOGE("failed to link elements");
3913 if (textbin[MMPLAYER_T_QUEUE].gst) {
3915 GstPad *ghostpad = NULL;
3917 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3919 LOGE("failed to get sink pad of text queue");
3923 ghostpad = gst_ghost_pad_new("text_sink", pad);
3924 gst_object_unref(pad);
3927 LOGE("failed to create ghostpad of textbin");
3931 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3932 LOGE("failed to add ghostpad to textbin");
3933 gst_object_unref(ghostpad);
3938 g_list_free(element_bucket);
3940 return MM_ERROR_NONE;
3944 g_list_free(element_bucket);
3946 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3947 LOGE("remove textbin sink from sink list");
3948 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3951 /* release element at __mmplayer_gst_create_text_sink_bin */
3952 return MM_ERROR_PLAYER_INTERNAL;
3956 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3958 mmplayer_gst_element_t *textbin = NULL;
3959 int surface_type = 0;
3964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3967 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3969 LOGE("failed to allocate memory for textbin");
3970 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3974 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3975 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3976 if (!textbin[MMPLAYER_T_BIN].gst) {
3977 LOGE("failed to create textbin");
3982 player->pipeline->textbin = textbin;
3985 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3986 LOGD("surface type for subtitle : %d", surface_type);
3987 switch (surface_type) {
3988 case MM_DISPLAY_SURFACE_OVERLAY:
3989 case MM_DISPLAY_SURFACE_NULL:
3990 case MM_DISPLAY_SURFACE_REMOTE:
3991 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3992 LOGE("failed to make plain text elements");
4003 return MM_ERROR_NONE;
4007 LOGD("ERROR : releasing textbin");
4009 /* release signal */
4010 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4012 /* release element which are not added to bin */
4013 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4014 /* NOTE : skip bin */
4015 if (textbin[i].gst) {
4016 GstObject *parent = NULL;
4017 parent = gst_element_get_parent(textbin[i].gst);
4020 gst_object_unref(GST_OBJECT(textbin[i].gst));
4021 textbin[i].gst = NULL;
4023 gst_object_unref(GST_OBJECT(parent));
4028 /* release textbin with it's children */
4029 if (textbin[MMPLAYER_T_BIN].gst)
4030 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4032 MMPLAYER_FREEIF(textbin);
4033 player->pipeline->textbin = NULL;
4036 return MM_ERROR_PLAYER_INTERNAL;
4040 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4042 mmplayer_gst_element_t *mainbin = NULL;
4043 mmplayer_gst_element_t *textbin = NULL;
4044 MMHandleType attrs = 0;
4045 GstElement *subsrc = NULL;
4046 GstElement *subparse = NULL;
4047 gchar *subtitle_uri = NULL;
4048 const gchar *charset = NULL;
4054 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4056 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4058 mainbin = player->pipeline->mainbin;
4060 attrs = MMPLAYER_GET_ATTRS(player);
4062 LOGE("cannot get content attribute");
4063 return MM_ERROR_PLAYER_INTERNAL;
4066 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4067 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4068 LOGE("subtitle uri is not proper filepath.");
4069 return MM_ERROR_PLAYER_INVALID_URI;
4072 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4073 LOGE("failed to get storage info of subtitle path");
4074 return MM_ERROR_PLAYER_INVALID_URI;
4077 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4079 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4080 player->subtitle_language_list = NULL;
4081 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4083 /* create the subtitle source */
4084 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4086 LOGE("failed to create filesrc element");
4089 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4091 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4092 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4094 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4095 LOGW("failed to add queue");
4096 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4097 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4098 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4103 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4105 LOGE("failed to create subparse element");
4109 charset = _mmplayer_get_charset(subtitle_uri);
4111 LOGD("detected charset is %s", charset);
4112 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4115 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4116 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4118 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4119 LOGW("failed to add subparse");
4120 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4121 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4122 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4126 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4127 LOGW("failed to link subsrc and subparse");
4131 player->play_subtitle = TRUE;
4132 player->adjust_subtitle_pos = 0;
4134 LOGD("play subtitle using subtitle file");
4136 if (player->pipeline->textbin == NULL) {
4137 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4138 LOGE("failed to create text sink bin. continuing without text");
4142 textbin = player->pipeline->textbin;
4144 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4145 LOGW("failed to add textbin");
4147 /* release signal */
4148 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4150 /* release textbin with it's children */
4151 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4152 MMPLAYER_FREEIF(player->pipeline->textbin);
4153 player->pipeline->textbin = textbin = NULL;
4157 LOGD("link text input selector and textbin ghost pad");
4159 player->textsink_linked = 1;
4160 player->external_text_idx = 0;
4161 LOGI("textsink is linked");
4163 textbin = player->pipeline->textbin;
4164 LOGD("text bin has been created. reuse it.");
4165 player->external_text_idx = 1;
4168 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4169 LOGW("failed to link subparse and textbin");
4173 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4175 LOGE("failed to get sink pad from textsink to probe data");
4179 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4180 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4182 gst_object_unref(pad);
4185 /* create dot. for debugging */
4186 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4189 return MM_ERROR_NONE;
4192 /* release text pipeline resource */
4193 player->textsink_linked = 0;
4195 /* release signal */
4196 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4198 if (player->pipeline->textbin) {
4199 LOGE("remove textbin");
4201 /* release textbin with it's children */
4202 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4203 MMPLAYER_FREEIF(player->pipeline->textbin);
4204 player->pipeline->textbin = NULL;
4208 /* release subtitle elem */
4209 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4210 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4212 return MM_ERROR_PLAYER_INTERNAL;
4216 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4218 mmplayer_t *player = (mmplayer_t *)data;
4219 MMMessageParamType msg = {0, };
4220 GstClockTime duration = 0;
4221 gpointer text = NULL;
4222 guint text_size = 0;
4223 gboolean ret = TRUE;
4224 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4228 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4229 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4231 if (player->is_subtitle_force_drop) {
4232 LOGW("subtitle is dropped forcedly.");
4236 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4237 text = mapinfo.data;
4238 text_size = mapinfo.size;
4240 if (player->set_mode.subtitle_off) {
4241 LOGD("subtitle is OFF.");
4245 if (!text || (text_size == 0)) {
4246 LOGD("There is no subtitle to be displayed.");
4250 msg.data = (void *)text;
4252 duration = GST_BUFFER_DURATION(buffer);
4254 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4255 if (player->duration > GST_BUFFER_PTS(buffer))
4256 duration = player->duration - GST_BUFFER_PTS(buffer);
4259 LOGI("subtitle duration is invalid, subtitle duration change "
4260 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4262 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4264 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4266 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4267 gst_buffer_unmap(buffer, &mapinfo);
4274 static GstPadProbeReturn
4275 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4277 mmplayer_t *player = (mmplayer_t *)u_data;
4278 GstClockTime cur_timestamp = 0;
4279 gint64 adjusted_timestamp = 0;
4280 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4282 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4284 if (player->set_mode.subtitle_off) {
4285 LOGD("subtitle is OFF.");
4289 if (player->adjust_subtitle_pos == 0) {
4290 LOGD("nothing to do");
4294 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4295 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4297 if (adjusted_timestamp < 0) {
4298 LOGD("adjusted_timestamp under zero");
4303 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4304 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4305 GST_TIME_ARGS(cur_timestamp),
4306 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4308 return GST_PAD_PROBE_OK;
4312 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4316 /* check player and subtitlebin are created */
4317 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4318 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4320 if (position == 0) {
4321 LOGD("nothing to do");
4323 return MM_ERROR_NONE;
4326 /* check current position */
4327 player->adjust_subtitle_pos = position;
4329 LOGD("save adjust_subtitle_pos in player");
4333 return MM_ERROR_NONE;
4337 * This function is to create audio or video pipeline for playing.
4339 * @param player [in] handle of player
4341 * @return This function returns zero on success.
4346 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4348 int ret = MM_ERROR_NONE;
4349 mmplayer_gst_element_t *mainbin = NULL;
4350 MMHandleType attrs = 0;
4353 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4355 /* get profile attribute */
4356 attrs = MMPLAYER_GET_ATTRS(player);
4358 LOGE("failed to get content attribute");
4362 /* create pipeline handles */
4363 if (player->pipeline) {
4364 LOGE("pipeline should be released before create new one");
4368 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4370 /* create mainbin */
4371 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4372 if (mainbin == NULL)
4375 /* create pipeline */
4376 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4377 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4378 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4379 LOGE("failed to create pipeline");
4384 player->pipeline->mainbin = mainbin;
4386 /* create the source and decoder elements */
4387 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4388 ret = _mmplayer_gst_build_es_pipeline(player);
4390 if (MMPLAYER_USE_DECODEBIN(player))
4391 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4393 ret = _mmplayer_gst_build_pipeline_with_src(player);
4396 if (ret != MM_ERROR_NONE) {
4397 LOGE("failed to create some elements");
4401 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4402 if (__mmplayer_check_subtitle(player)
4403 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4404 LOGE("failed to create text pipeline");
4407 ret = _mmplayer_gst_add_bus_watch(player);
4408 if (ret != MM_ERROR_NONE) {
4409 LOGE("failed to add bus watch");
4414 return MM_ERROR_NONE;
4417 _mmplayer_bus_watcher_remove(player);
4418 __mmplayer_gst_destroy_pipeline(player);
4419 return MM_ERROR_PLAYER_INTERNAL;
4423 __mmplayer_reset_gapless_state(mmplayer_t *player)
4426 MMPLAYER_RETURN_IF_FAIL(player
4428 && player->pipeline->audiobin
4429 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4431 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4438 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4441 int ret = MM_ERROR_NONE;
4445 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4447 /* cleanup stuffs */
4448 MMPLAYER_FREEIF(player->type_caps_str);
4449 player->no_more_pad = FALSE;
4450 player->num_dynamic_pad = 0;
4452 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4453 player->subtitle_language_list = NULL;
4454 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4456 MMPLAYER_RECONFIGURE_LOCK(player);
4457 __mmplayer_reset_gapless_state(player);
4458 MMPLAYER_RECONFIGURE_UNLOCK(player);
4460 if (player->streamer) {
4461 _mm_player_streaming_initialize(player->streamer, FALSE);
4462 _mm_player_streaming_destroy(player->streamer);
4463 player->streamer = NULL;
4466 /* cleanup unlinked mime type */
4467 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4468 MMPLAYER_FREEIF(player->unlinked_video_mime);
4469 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4471 /* cleanup running stuffs */
4472 _mmplayer_cancel_eos_timer(player);
4474 /* cleanup gst stuffs */
4475 if (player->pipeline) {
4476 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4477 GstTagList *tag_list = player->pipeline->tag_list;
4479 /* first we need to disconnect all signal hander */
4480 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4483 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4484 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4485 gst_object_unref(bus);
4487 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4488 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4489 if (ret != MM_ERROR_NONE) {
4490 LOGE("fail to change state to NULL");
4491 return MM_ERROR_PLAYER_INTERNAL;
4494 LOGW("succeeded in changing state to NULL");
4496 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4499 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4500 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4502 MMPLAYER_FREEIF(player->pipeline->audiobin);
4503 MMPLAYER_FREEIF(player->pipeline->videobin);
4504 MMPLAYER_FREEIF(player->pipeline->textbin);
4505 MMPLAYER_FREEIF(mainbin);
4509 gst_tag_list_unref(tag_list);
4511 MMPLAYER_FREEIF(player->pipeline);
4513 MMPLAYER_FREEIF(player->album_art);
4515 if (player->v_stream_caps) {
4516 gst_caps_unref(player->v_stream_caps);
4517 player->v_stream_caps = NULL;
4520 if (player->a_stream_caps) {
4521 gst_caps_unref(player->a_stream_caps);
4522 player->a_stream_caps = NULL;
4525 if (player->s_stream_caps) {
4526 gst_caps_unref(player->s_stream_caps);
4527 player->s_stream_caps = NULL;
4529 _mmplayer_track_destroy(player);
4531 if (player->sink_elements)
4532 g_list_free(player->sink_elements);
4533 player->sink_elements = NULL;
4535 if (player->bufmgr) {
4536 tbm_bufmgr_deinit(player->bufmgr);
4537 player->bufmgr = NULL;
4540 LOGW("finished destroy pipeline");
4548 __mmplayer_gst_realize(mmplayer_t *player)
4551 int ret = MM_ERROR_NONE;
4555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4557 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4559 ret = __mmplayer_gst_create_pipeline(player);
4561 LOGE("failed to create pipeline");
4565 /* set pipeline state to READY */
4566 /* NOTE : state change to READY must be performed sync. */
4567 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4568 ret = _mmplayer_gst_set_state(player,
4569 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4571 if (ret != MM_ERROR_NONE) {
4572 /* return error if failed to set state */
4573 LOGE("failed to set READY state");
4577 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4579 /* create dot before error-return. for debugging */
4580 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4588 __mmplayer_gst_unrealize(mmplayer_t *player)
4590 int ret = MM_ERROR_NONE;
4594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4596 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4597 MMPLAYER_PRINT_STATE(player);
4599 /* release miscellaneous information */
4600 __mmplayer_release_misc(player);
4602 /* destroy pipeline */
4603 ret = __mmplayer_gst_destroy_pipeline(player);
4604 if (ret != MM_ERROR_NONE) {
4605 LOGE("failed to destroy pipeline");
4609 /* release miscellaneous information.
4610 these info needs to be released after pipeline is destroyed. */
4611 __mmplayer_release_misc_post(player);
4613 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4621 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4626 LOGW("set_message_callback is called with invalid player handle");
4627 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4630 player->msg_cb = callback;
4631 player->msg_cb_param = user_param;
4633 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4637 return MM_ERROR_NONE;
4641 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4643 int ret = MM_ERROR_NONE;
4648 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4649 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4650 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4652 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4654 if (strstr(uri, "es_buff://")) {
4655 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4656 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4657 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4658 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4660 tmp = g_ascii_strdown(uri, strlen(uri));
4661 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4662 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4664 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4666 } else if (strstr(uri, "mms://")) {
4667 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4668 } else if ((path = strstr(uri, "mem://"))) {
4669 ret = __mmplayer_set_mem_uri(data, path, param);
4671 ret = __mmplayer_set_file_uri(data, uri);
4674 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4675 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4676 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4677 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4679 /* dump parse result */
4680 SECURE_LOGW("incoming uri : %s", uri);
4681 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4682 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4690 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4693 mmplayer_t *player = NULL;
4694 MMMessageParamType msg = {0, };
4696 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4701 LOGE("user_data is null");
4705 player = (mmplayer_t *)user_data;
4707 if (!player->pipeline || !player->attrs) {
4708 LOGW("not initialized");
4712 LOGD("cmd lock player, cmd state : %d", player->cmd);
4713 MMPLAYER_CMD_LOCK(player);
4714 LOGD("cmd locked player");
4716 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4717 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4718 LOGW("player already destroyed");
4719 MMPLAYER_CMD_UNLOCK(player);
4723 player->interrupted_by_resource = TRUE;
4725 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4727 /* get last play position */
4728 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4729 msg.union_type = MM_MSG_UNION_TIME;
4730 msg.time.elapsed = pos;
4731 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4733 LOGW("failed to get play position.");
4736 LOGD("video resource conflict so, resource will be freed by unrealizing");
4737 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4738 LOGE("failed to unrealize");
4740 MMPLAYER_CMD_UNLOCK(player);
4742 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4743 player->hw_resource[res_idx] = NULL;
4747 return TRUE; /* release all the resources */
4751 __mmplayer_initialize_video_roi(mmplayer_t *player)
4753 player->video_roi.scale_x = 0.0;
4754 player->video_roi.scale_y = 0.0;
4755 player->video_roi.scale_width = 1.0;
4756 player->video_roi.scale_height = 1.0;
4760 _mmplayer_create_player(MMHandleType handle)
4762 int ret = MM_ERROR_PLAYER_INTERNAL;
4763 bool enabled = false;
4765 mmplayer_t *player = MM_PLAYER_CAST(handle);
4769 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4771 /* initialize player state */
4772 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4773 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4774 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4775 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4777 /* check current state */
4778 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4780 /* construct attributes */
4781 player->attrs = _mmplayer_construct_attribute(handle);
4783 if (!player->attrs) {
4784 LOGE("Failed to construct attributes");
4788 /* initialize gstreamer with configured parameter */
4789 if (!__mmplayer_init_gstreamer(player)) {
4790 LOGE("Initializing gstreamer failed");
4791 _mmplayer_deconstruct_attribute(handle);
4795 /* create lock. note that g_tread_init() has already called in gst_init() */
4796 g_mutex_init(&player->fsink_lock);
4798 /* create update tag lock */
4799 g_mutex_init(&player->update_tag_lock);
4801 /* create gapless play mutex */
4802 g_mutex_init(&player->gapless_play_thread_mutex);
4804 /* create gapless play cond */
4805 g_cond_init(&player->gapless_play_thread_cond);
4807 /* create gapless play thread */
4808 player->gapless_play_thread =
4809 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4810 if (!player->gapless_play_thread) {
4811 LOGE("failed to create gapless play thread");
4812 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4813 g_mutex_clear(&player->gapless_play_thread_mutex);
4814 g_cond_clear(&player->gapless_play_thread_cond);
4818 player->bus_msg_q = g_queue_new();
4819 if (!player->bus_msg_q) {
4820 LOGE("failed to create queue for bus_msg");
4821 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4825 ret = _mmplayer_initialize_video_capture(player);
4826 if (ret != MM_ERROR_NONE) {
4827 LOGW("video capture is not supported");
4828 /* do not handle as error for headless profile */
4831 /* initialize resource manager */
4832 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4833 __resource_release_cb, player, &player->resource_manager)
4834 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4835 LOGE("failed to create resource manager");
4836 ret = MM_ERROR_PLAYER_INTERNAL;
4840 /* create video bo lock and cond */
4841 g_mutex_init(&player->video_bo_mutex);
4842 g_cond_init(&player->video_bo_cond);
4844 /* create subtitle info lock and cond */
4845 g_mutex_init(&player->subtitle_info_mutex);
4846 g_cond_init(&player->subtitle_info_cond);
4848 player->streaming_type = STREAMING_SERVICE_NONE;
4850 /* give default value of audio effect setting */
4851 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4852 player->sound.rg_enable = false;
4853 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4855 player->play_subtitle = FALSE;
4856 player->has_closed_caption = FALSE;
4857 player->pending_resume = FALSE;
4858 if (player->ini.dump_element_keyword[0][0] == '\0')
4859 player->ini.set_dump_element_flag = FALSE;
4861 player->ini.set_dump_element_flag = TRUE;
4863 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4864 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4865 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4867 /* Set video360 settings to their defaults for just-created player.
4870 player->is_360_feature_enabled = FALSE;
4871 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4872 LOGI("spherical feature info: %d", enabled);
4874 player->is_360_feature_enabled = TRUE;
4876 LOGE("failed to get spherical feature info");
4879 player->is_content_spherical = FALSE;
4880 player->is_video360_enabled = TRUE;
4881 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4882 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4883 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4884 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4885 player->video360_zoom = 1.0f;
4886 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4887 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4889 __mmplayer_initialize_video_roi(player);
4891 /* set player state to null */
4892 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4893 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4897 return MM_ERROR_NONE;
4901 g_mutex_clear(&player->fsink_lock);
4902 /* free update tag lock */
4903 g_mutex_clear(&player->update_tag_lock);
4904 g_queue_free(player->bus_msg_q);
4905 player->bus_msg_q = NULL;
4906 /* free gapless play thread */
4907 if (player->gapless_play_thread) {
4908 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4909 player->gapless_play_thread_exit = TRUE;
4910 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4911 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4913 g_thread_join(player->gapless_play_thread);
4914 player->gapless_play_thread = NULL;
4916 g_mutex_clear(&player->gapless_play_thread_mutex);
4917 g_cond_clear(&player->gapless_play_thread_cond);
4920 /* release attributes */
4921 _mmplayer_deconstruct_attribute(handle);
4929 __mmplayer_init_gstreamer(mmplayer_t *player)
4931 static gboolean initialized = FALSE;
4932 static const int max_argc = 50;
4934 gchar **argv = NULL;
4935 gchar **argv2 = NULL;
4941 LOGD("gstreamer already initialized.");
4946 argc = malloc(sizeof(int));
4947 argv = malloc(sizeof(gchar *) * max_argc);
4948 argv2 = malloc(sizeof(gchar *) * max_argc);
4950 if (!argc || !argv || !argv2)
4953 memset(argv, 0, sizeof(gchar *) * max_argc);
4954 memset(argv2, 0, sizeof(gchar *) * max_argc);
4958 argv[0] = g_strdup("mmplayer");
4961 for (i = 0; i < 5; i++) {
4962 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4963 if (strlen(player->ini.gst_param[i]) > 0) {
4964 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4969 /* we would not do fork for scanning plugins */
4970 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4973 /* check disable registry scan */
4974 if (player->ini.skip_rescan) {
4975 argv[*argc] = g_strdup("--gst-disable-registry-update");
4979 /* check disable segtrap */
4980 if (player->ini.disable_segtrap) {
4981 argv[*argc] = g_strdup("--gst-disable-segtrap");
4985 LOGD("initializing gstreamer with following parameter");
4986 LOGD("argc : %d", *argc);
4989 for (i = 0; i < arg_count; i++) {
4991 LOGD("argv[%d] : %s", i, argv2[i]);
4994 /* initializing gstreamer */
4995 if (!gst_init_check(argc, &argv, &err)) {
4996 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
5003 for (i = 0; i < arg_count; i++) {
5005 LOGD("release - argv[%d] : %s", i, argv2[i]);
5007 MMPLAYER_FREEIF(argv2[i]);
5010 MMPLAYER_FREEIF(argv);
5011 MMPLAYER_FREEIF(argv2);
5012 MMPLAYER_FREEIF(argc);
5022 for (i = 0; i < arg_count; i++) {
5023 LOGD("free[%d] : %s", i, argv2[i]);
5024 MMPLAYER_FREEIF(argv2[i]);
5027 MMPLAYER_FREEIF(argv);
5028 MMPLAYER_FREEIF(argv2);
5029 MMPLAYER_FREEIF(argc);
5035 __mmplayer_check_async_state_transition(mmplayer_t *player)
5037 GstState element_state = GST_STATE_VOID_PENDING;
5038 GstState element_pending_state = GST_STATE_VOID_PENDING;
5039 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5040 GstElement *element = NULL;
5041 gboolean async = FALSE;
5043 /* check player handle */
5044 MMPLAYER_RETURN_IF_FAIL(player &&
5046 player->pipeline->mainbin &&
5047 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5050 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5052 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5053 LOGD("don't need to check the pipeline state");
5057 MMPLAYER_PRINT_STATE(player);
5059 /* wait for state transition */
5060 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5061 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5063 if (ret == GST_STATE_CHANGE_FAILURE) {
5064 LOGE(" [%s] state : %s pending : %s",
5065 GST_ELEMENT_NAME(element),
5066 gst_element_state_get_name(element_state),
5067 gst_element_state_get_name(element_pending_state));
5069 /* dump state of all element */
5070 _mmplayer_dump_pipeline_state(player);
5075 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5080 _mmplayer_destroy(MMHandleType handle)
5082 mmplayer_t *player = MM_PLAYER_CAST(handle);
5086 /* check player handle */
5087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5089 /* destroy can called at anytime */
5090 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5092 /* check async state transition */
5093 __mmplayer_check_async_state_transition(player);
5095 /* release gapless play thread */
5096 if (player->gapless_play_thread) {
5097 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5098 player->gapless_play_thread_exit = TRUE;
5099 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5100 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5102 LOGD("waiting for gapless play thread exit");
5103 g_thread_join(player->gapless_play_thread);
5104 g_mutex_clear(&player->gapless_play_thread_mutex);
5105 g_cond_clear(&player->gapless_play_thread_cond);
5106 LOGD("gapless play thread released");
5109 _mmplayer_release_video_capture(player);
5111 /* release miscellaneous information */
5112 __mmplayer_release_misc(player);
5114 /* release pipeline */
5115 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5116 LOGE("failed to destroy pipeline");
5117 return MM_ERROR_PLAYER_INTERNAL;
5120 __mmplayer_destroy_hw_resource(player);
5122 g_queue_free(player->bus_msg_q);
5124 /* release subtitle info lock and cond */
5125 g_mutex_clear(&player->subtitle_info_mutex);
5126 g_cond_clear(&player->subtitle_info_cond);
5128 __mmplayer_release_dump_list(player->dump_list);
5130 /* release miscellaneous information.
5131 these info needs to be released after pipeline is destroyed. */
5132 __mmplayer_release_misc_post(player);
5134 /* release attributes */
5135 _mmplayer_deconstruct_attribute(handle);
5137 if (player->uri_info.uri_list) {
5138 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5139 player->uri_info.uri_list = NULL;
5143 g_mutex_clear(&player->fsink_lock);
5146 g_mutex_clear(&player->update_tag_lock);
5148 /* release video bo lock and cond */
5149 g_mutex_clear(&player->video_bo_mutex);
5150 g_cond_clear(&player->video_bo_cond);
5154 return MM_ERROR_NONE;
5158 _mmplayer_realize(MMHandleType hplayer)
5160 mmplayer_t *player = (mmplayer_t *)hplayer;
5161 int ret = MM_ERROR_NONE;
5164 MMHandleType attrs = 0;
5168 /* check player handle */
5169 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5171 /* check current state */
5172 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5174 attrs = MMPLAYER_GET_ATTRS(player);
5176 LOGE("fail to get attributes.");
5177 return MM_ERROR_PLAYER_INTERNAL;
5179 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5180 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5182 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5183 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5185 if (ret != MM_ERROR_NONE) {
5186 LOGE("failed to parse profile");
5191 if (uri && (strstr(uri, "es_buff://"))) {
5192 if (strstr(uri, "es_buff://push_mode"))
5193 player->es_player_push_mode = TRUE;
5195 player->es_player_push_mode = FALSE;
5198 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5199 LOGW("mms protocol is not supported format.");
5200 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5203 if (MMPLAYER_IS_STREAMING(player))
5204 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5206 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5208 player->smooth_streaming = FALSE;
5209 player->videodec_linked = 0;
5210 player->audiodec_linked = 0;
5211 player->textsink_linked = 0;
5212 player->is_external_subtitle_present = FALSE;
5213 player->is_external_subtitle_added_now = FALSE;
5214 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5215 player->video360_metadata.is_spherical = -1;
5216 player->is_openal_plugin_used = FALSE;
5217 player->subtitle_language_list = NULL;
5218 player->is_subtitle_force_drop = FALSE;
5220 _mmplayer_track_initialize(player);
5221 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5223 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5224 gint prebuffer_ms = 0, rebuffer_ms = 0;
5226 player->streamer = _mm_player_streaming_create();
5227 _mm_player_streaming_initialize(player->streamer, TRUE);
5229 mm_attrs_multiple_get(player->attrs, NULL,
5230 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5231 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5233 if (prebuffer_ms > 0) {
5234 prebuffer_ms = MAX(prebuffer_ms, 1000);
5235 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5238 if (rebuffer_ms > 0) {
5239 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5240 rebuffer_ms = MAX(rebuffer_ms, 1000);
5241 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5244 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5245 player->streamer->buffering_req.rebuffer_time);
5248 /* realize pipeline */
5249 ret = __mmplayer_gst_realize(player);
5250 if (ret != MM_ERROR_NONE)
5251 LOGE("fail to realize the player.");
5253 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5261 _mmplayer_unrealize(MMHandleType hplayer)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5264 int ret = MM_ERROR_NONE;
5265 int rm_ret = MM_ERROR_NONE;
5266 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5270 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5272 MMPLAYER_CMD_UNLOCK(player);
5273 _mmplayer_bus_watcher_remove(player);
5274 /* destroy the gst bus msg thread which is created during realize.
5275 this funct have to be called before getting cmd lock. */
5276 _mmplayer_bus_msg_thread_destroy(player);
5277 MMPLAYER_CMD_LOCK(player);
5279 /* check current state */
5280 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5282 /* check async state transition */
5283 __mmplayer_check_async_state_transition(player);
5285 /* unrealize pipeline */
5286 ret = __mmplayer_gst_unrealize(player);
5288 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5289 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5290 if (rm_ret != MM_ERROR_NONE)
5291 LOGE("failed to release [%d] resources", res_idx);
5294 player->interrupted_by_resource = FALSE;
5301 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5303 mmplayer_t *player = (mmplayer_t *)hplayer;
5305 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5311 _mmplayer_get_state(MMHandleType hplayer, int *state)
5313 mmplayer_t *player = (mmplayer_t *)hplayer;
5315 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5317 *state = MMPLAYER_CURRENT_STATE(player);
5319 return MM_ERROR_NONE;
5323 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5325 GstElement *vol_element = NULL;
5326 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5330 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5332 /* check pipeline handle */
5333 if (!player->pipeline || !player->pipeline->audiobin) {
5334 LOGD("'%s' will be applied when audiobin is created", prop_name);
5336 /* NOTE : stored value will be used in create_audiobin
5337 * returning MM_ERROR_NONE here makes application to able to
5338 * set audio volume or mute at anytime.
5340 return MM_ERROR_NONE;
5343 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5344 volume_elem_id = MMPLAYER_A_SINK;
5346 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5348 LOGE("failed to get vol element %d", volume_elem_id);
5349 return MM_ERROR_PLAYER_INTERNAL;
5352 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5354 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5355 LOGE("there is no '%s' property", prop_name);
5356 return MM_ERROR_PLAYER_INTERNAL;
5359 if (!strcmp(prop_name, "volume")) {
5360 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5361 } else if (!strcmp(prop_name, "mute")) {
5362 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5364 LOGE("invalid property %s", prop_name);
5365 return MM_ERROR_PLAYER_INTERNAL;
5368 return MM_ERROR_NONE;
5372 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5374 int ret = MM_ERROR_NONE;
5375 mmplayer_t *player = (mmplayer_t *)hplayer;
5378 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5380 LOGD("volume = %f", volume);
5382 /* invalid factor range or not */
5383 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5384 LOGE("Invalid volume value");
5385 return MM_ERROR_INVALID_ARGUMENT;
5388 player->sound.volume = volume;
5390 ret = __mmplayer_gst_set_volume_property(player, "volume");
5397 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5399 mmplayer_t *player = (mmplayer_t *)hplayer;
5403 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5404 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5406 *volume = player->sound.volume;
5408 LOGD("current vol = %f", *volume);
5411 return MM_ERROR_NONE;
5415 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5417 int ret = MM_ERROR_NONE;
5418 mmplayer_t *player = (mmplayer_t *)hplayer;
5421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5423 LOGD("mute = %d", mute);
5425 player->sound.mute = mute;
5427 ret = __mmplayer_gst_set_volume_property(player, "mute");
5434 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5436 mmplayer_t *player = (mmplayer_t *)hplayer;
5440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5441 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5443 *mute = player->sound.mute;
5445 LOGD("current mute = %d", *mute);
5449 return MM_ERROR_NONE;
5453 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5455 mmplayer_t *player = (mmplayer_t *)hplayer;
5459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5461 player->audio_stream_changed_cb = callback;
5462 player->audio_stream_changed_cb_user_param = user_param;
5463 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5467 return MM_ERROR_NONE;
5471 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5473 mmplayer_t *player = (mmplayer_t *)hplayer;
5477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5479 player->audio_decoded_cb = callback;
5480 player->audio_decoded_cb_user_param = user_param;
5481 player->audio_extract_opt = opt;
5482 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5486 return MM_ERROR_NONE;
5490 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5492 mmplayer_t *player = (mmplayer_t *)hplayer;
5496 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5498 if (callback && !player->bufmgr)
5499 player->bufmgr = tbm_bufmgr_init(-1);
5501 player->set_mode.video_export = (callback) ? true : false;
5502 player->video_decoded_cb = callback;
5503 player->video_decoded_cb_user_param = user_param;
5505 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5509 return MM_ERROR_NONE;
5513 _mmplayer_start(MMHandleType hplayer)
5515 mmplayer_t *player = (mmplayer_t *)hplayer;
5516 gint ret = MM_ERROR_NONE;
5520 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5522 /* check current state */
5523 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5525 /* start pipeline */
5526 ret = _mmplayer_gst_start(player);
5527 if (ret != MM_ERROR_NONE)
5528 LOGE("failed to start player.");
5530 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5531 LOGD("force playing start even during buffering");
5532 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5540 /* NOTE: post "not supported codec message" to application
5541 * when one codec is not found during AUTOPLUGGING in MSL.
5542 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5543 * And, if any codec is not found, don't send message here.
5544 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5547 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5549 MMMessageParamType msg_param;
5550 memset(&msg_param, 0, sizeof(MMMessageParamType));
5551 gboolean post_msg_direct = FALSE;
5555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5557 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5558 player->not_supported_codec, player->can_support_codec);
5560 if (player->not_found_demuxer) {
5561 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5562 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5564 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5565 MMPLAYER_FREEIF(msg_param.data);
5567 return MM_ERROR_NONE;
5570 if (player->not_supported_codec) {
5571 if (player->can_support_codec) {
5572 // There is one codec to play
5573 post_msg_direct = TRUE;
5575 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5576 post_msg_direct = TRUE;
5579 if (post_msg_direct) {
5580 MMMessageParamType msg_param;
5581 memset(&msg_param, 0, sizeof(MMMessageParamType));
5583 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5584 LOGW("not found AUDIO codec, posting error code to application.");
5586 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5587 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5588 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5589 LOGW("not found VIDEO codec, posting error code to application.");
5591 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5592 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5595 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5597 MMPLAYER_FREEIF(msg_param.data);
5599 return MM_ERROR_NONE;
5601 // no any supported codec case
5602 LOGW("not found any codec, posting error code to application.");
5604 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5605 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5606 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5608 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5609 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5612 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5614 MMPLAYER_FREEIF(msg_param.data);
5620 return MM_ERROR_NONE;
5623 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5625 GstState element_state = GST_STATE_VOID_PENDING;
5626 GstState element_pending_state = GST_STATE_VOID_PENDING;
5627 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5628 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5630 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5632 MMPLAYER_RECONFIGURE_LOCK(player);
5633 if (!player->gapless.reconfigure) {
5634 MMPLAYER_RECONFIGURE_UNLOCK(player);
5638 LOGI("reconfigure is under process");
5639 MMPLAYER_RECONFIGURE_WAIT(player);
5640 MMPLAYER_RECONFIGURE_UNLOCK(player);
5641 LOGI("reconfigure is completed.");
5643 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5644 &element_state, &element_pending_state, timeout * GST_SECOND);
5645 if (result == GST_STATE_CHANGE_FAILURE)
5646 LOGW("failed to get pipeline state in %d sec", timeout);
5651 /* NOTE : it should be able to call 'stop' anytime*/
5653 _mmplayer_stop(MMHandleType hplayer)
5655 mmplayer_t *player = (mmplayer_t *)hplayer;
5656 int ret = MM_ERROR_NONE;
5660 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5662 /* check current state */
5663 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5665 /* need to wait till the rebuilding pipeline is completed */
5666 __mmplayer_check_pipeline_reconfigure_state(player);
5667 MMPLAYER_RECONFIGURE_LOCK(player);
5668 __mmplayer_reset_gapless_state(player);
5669 MMPLAYER_RECONFIGURE_UNLOCK(player);
5671 /* NOTE : application should not wait for EOS after calling STOP */
5672 _mmplayer_cancel_eos_timer(player);
5675 player->seek_state = MMPLAYER_SEEK_NONE;
5678 ret = _mmplayer_gst_stop(player);
5680 if (ret != MM_ERROR_NONE)
5681 LOGE("failed to stop player.");
5689 _mmplayer_pause(MMHandleType hplayer)
5691 mmplayer_t *player = (mmplayer_t *)hplayer;
5692 gint64 pos_nsec = 0;
5693 gboolean async = FALSE;
5694 gint ret = MM_ERROR_NONE;
5698 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5700 /* check current state */
5701 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5703 /* check pipeline reconfigure state */
5704 __mmplayer_check_pipeline_reconfigure_state(player);
5706 switch (MMPLAYER_CURRENT_STATE(player)) {
5707 case MM_PLAYER_STATE_READY:
5709 /* check prepare async or not.
5710 * In the case of streaming playback, it's recommended to avoid blocking wait.
5712 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5713 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5715 /* Changing back sync of rtspsrc to async */
5716 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5717 LOGD("async prepare working mode for rtsp");
5723 case MM_PLAYER_STATE_PLAYING:
5725 /* NOTE : store current point to overcome some bad operation
5726 *(returning zero when getting current position in paused state) of some
5729 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5730 LOGW("getting current position failed in paused");
5732 player->last_position = pos_nsec;
5734 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5735 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5736 This causes problem is position calculation during normal pause resume scenarios also.
5737 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5738 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5739 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5740 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5746 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5747 LOGD("doing async pause in case of ms buff src");
5751 /* pause pipeline */
5752 ret = _mmplayer_gst_pause(player, async);
5753 if (ret != MM_ERROR_NONE) {
5754 LOGE("failed to pause player. ret : 0x%x", ret);
5755 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5759 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5760 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5761 LOGE("failed to update display_rotation");
5765 return MM_ERROR_NONE;
5768 /* in case of streaming, pause could take long time.*/
5770 _mmplayer_abort_pause(MMHandleType hplayer)
5772 mmplayer_t *player = (mmplayer_t *)hplayer;
5773 int ret = MM_ERROR_NONE;
5777 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5779 player->pipeline->mainbin,
5780 MM_ERROR_PLAYER_NOT_INITIALIZED);
5782 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5783 LOGD("set the videobin state to READY");
5784 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5785 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5789 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5790 LOGD("set the audiobin state to READY");
5791 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5792 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5796 LOGD("set the pipeline state to READY");
5797 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5798 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5800 if (ret != MM_ERROR_NONE) {
5801 LOGE("fail to change state to READY");
5802 return MM_ERROR_PLAYER_INTERNAL;
5805 LOGD("succeeded in changing state to READY");
5810 _mmplayer_resume(MMHandleType hplayer)
5812 mmplayer_t *player = (mmplayer_t *)hplayer;
5813 int ret = MM_ERROR_NONE;
5814 gboolean async = FALSE;
5818 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5820 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5821 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5822 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5826 /* Changing back sync mode rtspsrc to async */
5827 LOGD("async resume for rtsp case");
5831 /* check current state */
5832 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5834 ret = _mmplayer_gst_resume(player, async);
5835 if (ret != MM_ERROR_NONE)
5836 LOGE("failed to resume player.");
5838 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5839 LOGD("force resume even during buffering");
5840 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5849 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5851 mmplayer_t *player = (mmplayer_t *)hplayer;
5852 gint64 pos_nsec = 0;
5853 int ret = MM_ERROR_NONE;
5855 signed long long start = 0, stop = 0;
5856 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5859 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5860 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5862 /* The sound of video is not supported under 0.0 and over 2.0. */
5863 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5864 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5867 _mmplayer_set_mute(hplayer, mute);
5869 if (player->playback_rate == rate)
5870 return MM_ERROR_NONE;
5872 /* If the position is reached at start potion during fast backward, EOS is posted.
5873 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5875 player->playback_rate = rate;
5877 current_state = MMPLAYER_CURRENT_STATE(player);
5879 if (current_state != MM_PLAYER_STATE_PAUSED)
5880 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5882 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5884 if ((current_state == MM_PLAYER_STATE_PAUSED)
5885 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5886 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5887 pos_nsec = player->last_position;
5892 stop = GST_CLOCK_TIME_NONE;
5894 start = GST_CLOCK_TIME_NONE;
5898 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5899 player->playback_rate,
5901 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5902 GST_SEEK_TYPE_SET, start,
5903 GST_SEEK_TYPE_SET, stop)) {
5904 LOGE("failed to set speed playback");
5905 return MM_ERROR_PLAYER_SEEK;
5908 LOGD("succeeded to set speed playback as %0.1f", rate);
5912 return MM_ERROR_NONE;;
5916 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5918 mmplayer_t *player = (mmplayer_t *)hplayer;
5919 int ret = MM_ERROR_NONE;
5923 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5925 /* check pipeline reconfigure state */
5926 __mmplayer_check_pipeline_reconfigure_state(player);
5928 ret = _mmplayer_gst_set_position(player, position, FALSE);
5936 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5938 mmplayer_t *player = (mmplayer_t *)hplayer;
5939 int ret = MM_ERROR_NONE;
5941 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5942 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5944 if (g_strrstr(player->type_caps_str, "video/mpegts"))
5945 __mmplayer_update_duration_value(player);
5947 *duration = player->duration;
5952 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5954 mmplayer_t *player = (mmplayer_t *)hplayer;
5955 int ret = MM_ERROR_NONE;
5957 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5959 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5965 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5967 mmplayer_t *player = (mmplayer_t *)hplayer;
5968 int ret = MM_ERROR_NONE;
5972 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5974 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5982 __mmplayer_is_midi_type(gchar *str_caps)
5984 if ((g_strrstr(str_caps, "audio/midi")) ||
5985 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5986 (g_strrstr(str_caps, "application/x-smaf")) ||
5987 (g_strrstr(str_caps, "audio/x-imelody")) ||
5988 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5989 (g_strrstr(str_caps, "audio/xmf")) ||
5990 (g_strrstr(str_caps, "audio/mxmf"))) {
5999 __mmplayer_is_only_mp3_type(gchar *str_caps)
6001 if (g_strrstr(str_caps, "application/x-id3") ||
6002 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
6008 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
6010 GstStructure *caps_structure = NULL;
6011 gint samplerate = 0;
6015 MMPLAYER_RETURN_IF_FAIL(player && caps);
6017 caps_structure = gst_caps_get_structure(caps, 0);
6019 /* set stream information */
6020 gst_structure_get_int(caps_structure, "rate", &samplerate);
6021 gst_structure_get_int(caps_structure, "channels", &channels);
6023 mm_player_set_attribute((MMHandleType)player, NULL,
6024 "content_audio_samplerate", samplerate,
6025 "content_audio_channels", channels, NULL);
6027 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6031 __mmplayer_update_content_type_info(mmplayer_t *player)
6034 MMPLAYER_RETURN_IF_FAIL(player && player->type_caps_str);
6036 if (__mmplayer_is_midi_type(player->type_caps_str)) {
6037 player->bypass_audio_effect = TRUE;
6041 if (!player->streamer) {
6042 LOGD("no need to check streaming type");
6046 if (g_strrstr(player->type_caps_str, "application/x-hls")) {
6047 /* If it can't know exact type when it parses uri because of redirection case,
6048 * it will be fixed by typefinder or when doing autoplugging.
6050 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6051 player->streamer->is_adaptive_streaming = TRUE;
6052 } else if (g_strrstr(player->type_caps_str, "application/dash+xml")) {
6053 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6054 player->streamer->is_adaptive_streaming = TRUE;
6057 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6058 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type_caps_str, "video/mpegts"))) {
6059 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6061 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6062 if (player->streamer->is_adaptive_streaming)
6063 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6065 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6069 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6074 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6075 GstCaps *caps, gpointer data)
6077 mmplayer_t *player = (mmplayer_t *)data;
6081 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6083 MMPLAYER_FREEIF(player->type_caps_str);
6084 player->type_caps_str = gst_caps_to_string(caps);
6085 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6086 player, player->type_caps_str, probability, gst_caps_get_size(caps));
6088 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6089 (g_strrstr(player->type_caps_str, "audio/x-raw-int"))) {
6090 LOGE("not support media format");
6092 if (player->msg_posted == FALSE) {
6093 MMMessageParamType msg_param;
6094 memset(&msg_param, 0, sizeof(MMMessageParamType));
6096 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6097 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6099 /* don't post more if one was sent already */
6100 player->msg_posted = TRUE;
6105 __mmplayer_update_content_type_info(player);
6107 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6110 pad = gst_element_get_static_pad(tf, "src");
6112 LOGE("fail to get typefind src pad.");
6116 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6117 gboolean async = FALSE;
6118 LOGE("failed to autoplug %s", player->type_caps_str);
6120 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6122 if (async && player->msg_posted == FALSE)
6123 __mmplayer_handle_missed_plugin(player);
6125 gst_object_unref(GST_OBJECT(pad));
6132 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6134 GstElement *decodebin = NULL;
6138 /* create decodebin */
6139 decodebin = gst_element_factory_make("decodebin", NULL);
6142 LOGE("fail to create decodebin");
6146 /* raw pad handling signal */
6147 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6148 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6150 /* no-more-pad pad handling signal */
6151 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6152 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6154 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6155 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6157 /* This signal is emitted when a pad for which there is no further possible
6158 decoding is added to the decodebin.*/
6159 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6160 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6162 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6163 before looking for any elements that can handle that stream.*/
6164 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6165 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6167 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6168 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6169 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6171 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6172 before looking for any elements that can handle that stream.*/
6173 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6174 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6176 /* This signal is emitted once decodebin has finished decoding all the data.*/
6177 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6178 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6180 /* This signal is emitted when a element is added to the bin.*/
6181 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6182 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6189 __mmplayer_gst_make_queue2(mmplayer_t *player)
6191 GstElement *queue2 = NULL;
6192 gint64 dur_bytes = 0L;
6193 mmplayer_gst_element_t *mainbin = NULL;
6194 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6197 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6199 mainbin = player->pipeline->mainbin;
6201 queue2 = gst_element_factory_make("queue2", "queue2");
6203 LOGE("failed to create buffering queue element");
6207 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6208 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6210 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6212 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6213 * skip the pull mode(file or ring buffering) setting. */
6214 if (dur_bytes > 0) {
6215 if (!g_strrstr(player->type_caps_str, "video/mpegts")) {
6216 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6217 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6223 _mm_player_streaming_set_queue2(player->streamer,
6227 (guint64)dur_bytes); /* no meaning at the moment */
6233 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6235 mmplayer_gst_element_t *mainbin = NULL;
6236 GstElement *decodebin = NULL;
6237 GstElement *queue2 = NULL;
6238 GstPad *sinkpad = NULL;
6239 GstPad *qsrcpad = NULL;
6242 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6244 mainbin = player->pipeline->mainbin;
6246 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6248 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6249 LOGW("need to check: muxed buffer is not null");
6252 queue2 = __mmplayer_gst_make_queue2(player);
6254 LOGE("failed to make queue2");
6258 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6259 LOGE("failed to add buffering queue");
6263 sinkpad = gst_element_get_static_pad(queue2, "sink");
6264 qsrcpad = gst_element_get_static_pad(queue2, "src");
6266 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6267 LOGE("failed to link [%s:%s]-[%s:%s]",
6268 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6272 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6273 LOGE("failed to sync queue2 state with parent");
6277 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6278 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6282 gst_object_unref(GST_OBJECT(sinkpad));
6286 /* create decodebin */
6287 decodebin = _mmplayer_gst_make_decodebin(player);
6289 LOGE("failed to make decodebin");
6293 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6294 LOGE("failed to add decodebin");
6298 /* to force caps on the decodebin element and avoid reparsing stuff by
6299 * typefind. It also avoids a deadlock in the way typefind activates pads in
6300 * the state change */
6301 g_object_set(decodebin, "sink-caps", caps, NULL);
6303 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6305 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6306 LOGE("failed to link [%s:%s]-[%s:%s]",
6307 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6311 gst_object_unref(GST_OBJECT(sinkpad));
6313 gst_object_unref(GST_OBJECT(qsrcpad));
6316 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6317 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6319 /* set decodebin property about buffer in streaming playback. *
6320 * in case of HLS/DASH, it does not need to have big buffer *
6321 * because it is kind of adaptive streaming. */
6322 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6323 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6324 gint high_percent = 0;
6326 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6327 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6329 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6331 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6333 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6334 "high-percent", high_percent,
6335 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6336 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6337 "max-size-buffers", 0, NULL); // disable or automatic
6340 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6341 LOGE("failed to sync decodebin state with parent");
6352 gst_object_unref(GST_OBJECT(sinkpad));
6355 gst_object_unref(GST_OBJECT(qsrcpad));
6358 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6359 * You need to explicitly set elements to the NULL state before
6360 * dropping the final reference, to allow them to clean up.
6362 gst_element_set_state(queue2, GST_STATE_NULL);
6364 /* And, it still has a parent "player".
6365 * You need to let the parent manage the object instead of unreffing the object directly.
6367 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6368 LOGE("failed to remove queue2");
6369 gst_object_unref(queue2);
6375 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6376 * You need to explicitly set elements to the NULL state before
6377 * dropping the final reference, to allow them to clean up.
6379 gst_element_set_state(decodebin, GST_STATE_NULL);
6381 /* And, it still has a parent "player".
6382 * You need to let the parent manage the object instead of unreffing the object directly.
6385 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6386 LOGE("failed to remove decodebin");
6387 gst_object_unref(decodebin);
6396 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6400 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6401 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6403 LOGD("class : %s, mime : %s", factory_class, mime);
6405 /* add missing plugin */
6406 /* NOTE : msl should check missing plugin for image mime type.
6407 * Some motion jpeg clips can have playable audio track.
6408 * So, msl have to play audio after displaying popup written video format not supported.
6410 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6411 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6412 LOGD("not found demuxer");
6413 player->not_found_demuxer = TRUE;
6414 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6420 if (!g_strrstr(factory_class, "Demuxer")) {
6421 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6422 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6423 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6425 /* check that clip have multi tracks or not */
6426 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6427 LOGD("video plugin is already linked");
6429 LOGW("add VIDEO to missing plugin");
6430 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6431 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6433 } else if (g_str_has_prefix(mime, "audio")) {
6434 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6435 LOGD("audio plugin is already linked");
6437 LOGW("add AUDIO to missing plugin");
6438 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6439 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6447 return MM_ERROR_NONE;
6451 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6453 mmplayer_t *player = (mmplayer_t *)data;
6457 MMPLAYER_RETURN_IF_FAIL(player);
6459 /* remove fakesink. */
6460 if (!_mmplayer_gst_remove_fakesink(player,
6461 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6462 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6463 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6464 * source element are not same. To overcome this situation, this function will called
6465 * several places and several times. Therefore, this is not an error case.
6470 LOGD("[handle: %p] pipeline has completely constructed", player);
6472 if ((player->msg_posted == FALSE) &&
6473 (player->cmd >= MMPLAYER_COMMAND_START))
6474 __mmplayer_handle_missed_plugin(player);
6476 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6480 __mmplayer_check_profile(void)
6483 static int profile_tv = -1;
6485 if (__builtin_expect(profile_tv != -1, 1))
6488 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6489 switch (*profileName) {
6504 __mmplayer_get_next_uri(mmplayer_t *player)
6506 mmplayer_parse_profile_t profile;
6508 guint num_of_list = 0;
6511 num_of_list = g_list_length(player->uri_info.uri_list);
6512 uri_idx = player->uri_info.uri_idx;
6514 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6515 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6516 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6518 LOGW("next uri does not exist");
6522 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6523 LOGE("failed to parse profile");
6527 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6528 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6529 LOGW("uri type is not supported(%d)", profile.uri_type);
6533 LOGD("success to find next uri %d", uri_idx);
6537 if (!uri || uri_idx == num_of_list) {
6538 LOGE("failed to find next uri");
6542 player->uri_info.uri_idx = uri_idx;
6543 if (mm_player_set_attribute((MMHandleType)player, NULL,
6544 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6545 LOGE("failed to set attribute");
6549 if (!MMPLAYER_USE_DECODEBIN(player)) {
6550 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6551 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6552 "uri", profile.uri, NULL);
6555 SECURE_LOGD("next playback uri: %s", uri);
6560 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6562 #define REPEAT_COUNT_INFINITE -1
6563 #define REPEAT_COUNT_MIN 2
6564 #define ORIGINAL_URI_ONLY 1
6566 MMHandleType attrs = 0;
6570 guint num_of_uri = 0;
6571 int profile_tv = -1;
6575 LOGD("checking for gapless play option");
6577 if (player->build_audio_offload) {
6578 LOGE("offload path is not supportable.");
6582 if (player->pipeline->textbin) {
6583 LOGE("subtitle path is enabled. gapless play is not supported.");
6587 attrs = MMPLAYER_GET_ATTRS(player);
6589 LOGE("fail to get attributes.");
6593 mm_attrs_multiple_get(player->attrs, NULL,
6594 "content_video_found", &video,
6595 "profile_play_count", &count,
6596 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6598 /* gapless playback is not supported in case of video at TV profile. */
6599 profile_tv = __mmplayer_check_profile();
6600 if (profile_tv && video) {
6601 LOGW("not support video gapless playback");
6605 /* check repeat count in case of audio */
6607 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6608 LOGW("gapless is disabled");
6612 num_of_uri = g_list_length(player->uri_info.uri_list);
6613 if (!MMPLAYER_USE_DECODEBIN(player))
6614 player->gapless.running = TRUE;
6616 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6618 if (num_of_uri == ORIGINAL_URI_ONLY) {
6619 /* audio looping path */
6620 if (count >= REPEAT_COUNT_MIN) {
6621 /* decrease play count */
6622 /* we succeeded to rewind. update play count and then wait for next EOS */
6624 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6625 } else if (count != REPEAT_COUNT_INFINITE) {
6626 LOGD("there is no next uri and no repeat");
6630 if (!MMPLAYER_USE_DECODEBIN(player)) {
6631 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6632 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6633 "uri", player->profile.uri, NULL);
6636 LOGD("looping cnt %d", count);
6638 /* gapless playback path */
6639 if (!__mmplayer_get_next_uri(player)) {
6640 LOGE("failed to get next uri");
6647 LOGE("unable to play gapless path. EOS will be posted soon");
6652 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6654 GstPad *sinkpad = g_value_get_object (item);
6655 GstElement *element = GST_ELEMENT(user_data);
6656 if (!sinkpad || !element) {
6657 LOGE("invalid parameter");
6661 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6662 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6666 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6668 mmplayer_gst_element_t *sinkbin = NULL;
6669 main_element_id_e concatId = MMPLAYER_M_NUM;
6670 main_element_id_e sinkId = MMPLAYER_M_NUM;
6671 gboolean send_notice = FALSE;
6672 GstElement *element;
6676 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6678 LOGD("type %d", type);
6681 case MM_PLAYER_TRACK_TYPE_AUDIO:
6682 concatId = MMPLAYER_M_A_CONCAT;
6683 sinkId = MMPLAYER_A_BIN;
6684 sinkbin = player->pipeline->audiobin;
6686 case MM_PLAYER_TRACK_TYPE_VIDEO:
6687 concatId = MMPLAYER_M_V_CONCAT;
6688 sinkId = MMPLAYER_V_BIN;
6689 sinkbin = player->pipeline->videobin;
6692 case MM_PLAYER_TRACK_TYPE_TEXT:
6693 concatId = MMPLAYER_M_T_CONCAT;
6694 sinkId = MMPLAYER_T_BIN;
6695 sinkbin = player->pipeline->textbin;
6698 LOGE("requested type is not supportable");
6703 element = player->pipeline->mainbin[concatId].gst;
6707 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6708 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6709 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6710 if (srcpad && sinkpad) {
6711 /* after getting drained signal there is no data flows, so no need to do pad_block */
6712 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6713 gst_pad_unlink(srcpad, sinkpad);
6715 /* send custom event to sink pad to handle it at video sink */
6717 LOGD("send custom event to sinkpad");
6718 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6719 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6720 gst_pad_send_event(sinkpad, event);
6723 gst_object_unref(srcpad);
6724 gst_object_unref(sinkpad);
6727 LOGD("release concat request pad");
6728 /* release and unref requests pad from the selector */
6729 iter = gst_element_iterate_sink_pads(element);
6730 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6731 gst_iterator_resync(iter);
6732 gst_iterator_free(iter);
6738 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6740 mmplayer_track_t *selector = &player->track[type];
6741 mmplayer_gst_element_t *sinkbin = NULL;
6742 main_element_id_e selectorId = MMPLAYER_M_NUM;
6743 main_element_id_e sinkId = MMPLAYER_M_NUM;
6744 GstPad *srcpad = NULL;
6745 GstPad *sinkpad = NULL;
6746 gboolean send_notice = FALSE;
6749 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6751 LOGD("type %d", type);
6754 case MM_PLAYER_TRACK_TYPE_AUDIO:
6755 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6756 sinkId = MMPLAYER_A_BIN;
6757 sinkbin = player->pipeline->audiobin;
6759 case MM_PLAYER_TRACK_TYPE_VIDEO:
6760 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6761 sinkId = MMPLAYER_V_BIN;
6762 sinkbin = player->pipeline->videobin;
6765 case MM_PLAYER_TRACK_TYPE_TEXT:
6766 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6767 sinkId = MMPLAYER_T_BIN;
6768 sinkbin = player->pipeline->textbin;
6771 LOGE("requested type is not supportable");
6776 if (player->pipeline->mainbin[selectorId].gst) {
6779 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6781 if (selector->event_probe_id != 0)
6782 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6783 selector->event_probe_id = 0;
6785 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6786 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6788 if (srcpad && sinkpad) {
6789 /* after getting drained signal there is no data flows, so no need to do pad_block */
6790 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6791 gst_pad_unlink(srcpad, sinkpad);
6793 /* send custom event to sink pad to handle it at video sink */
6795 LOGD("send custom event to sinkpad");
6796 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6797 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6798 gst_pad_send_event(sinkpad, event);
6802 gst_object_unref(sinkpad);
6805 gst_object_unref(srcpad);
6808 LOGD("selector release");
6810 /* release and unref requests pad from the selector */
6811 for (n = 0; n < selector->streams->len; n++) {
6812 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6813 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6816 g_ptr_array_set_size(selector->streams, 0);
6818 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6819 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6820 player->pipeline->mainbin[selectorId].gst)) {
6821 LOGE("failed to remove selector");
6822 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6825 player->pipeline->mainbin[selectorId].gst = NULL;
6833 __mmplayer_deactivate_old_path(mmplayer_t *player)
6836 MMPLAYER_RETURN_IF_FAIL(player);
6838 if (MMPLAYER_USE_DECODEBIN(player)) {
6839 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6840 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6841 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6842 LOGE("deactivate selector error");
6846 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6847 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6848 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6849 LOGE("deactivate concat error");
6854 _mmplayer_track_destroy(player);
6855 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6857 if (player->streamer) {
6858 _mm_player_streaming_initialize(player->streamer, FALSE);
6859 _mm_player_streaming_destroy(player->streamer);
6860 player->streamer = NULL;
6863 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6869 if (!player->msg_posted) {
6870 MMMessageParamType msg = {0,};
6873 msg.code = MM_ERROR_PLAYER_INTERNAL;
6874 LOGE("gapless_uri_play> deactivate error");
6876 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6877 player->msg_posted = TRUE;
6883 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6885 int result = MM_ERROR_NONE;
6886 mmplayer_t *player = (mmplayer_t *)hplayer;
6889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6890 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6892 if (mm_player_set_attribute(hplayer, NULL,
6893 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6894 LOGE("failed to set attribute");
6895 result = MM_ERROR_PLAYER_INTERNAL;
6897 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6898 LOGE("failed to add the original uri in the uri list.");
6906 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6908 mmplayer_t *player = (mmplayer_t *)hplayer;
6909 guint num_of_list = 0;
6913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6914 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6916 if (player->pipeline && player->pipeline->textbin) {
6917 LOGE("subtitle path is enabled.");
6918 return MM_ERROR_PLAYER_INVALID_STATE;
6921 num_of_list = g_list_length(player->uri_info.uri_list);
6923 if (is_first_path) {
6924 if (num_of_list == 0) {
6925 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6926 SECURE_LOGD("add original path : %s", uri);
6928 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6929 player->uri_info.uri_list = g_list_prepend(
6930 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6931 SECURE_LOGD("change original path : %s", uri);
6934 MMHandleType attrs = 0;
6935 attrs = MMPLAYER_GET_ATTRS(player);
6937 if (num_of_list == 0) {
6938 char *original_uri = NULL;
6941 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6943 if (!original_uri) {
6944 LOGE("there is no original uri.");
6945 return MM_ERROR_PLAYER_INVALID_STATE;
6948 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6949 player->uri_info.uri_idx = 0;
6951 SECURE_LOGD("add original path at first : %s", original_uri);
6955 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6956 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6960 return MM_ERROR_NONE;
6964 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6966 mmplayer_t *player = (mmplayer_t *)hplayer;
6967 char *next_uri = NULL;
6968 guint num_of_list = 0;
6971 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6973 num_of_list = g_list_length(player->uri_info.uri_list);
6975 if (num_of_list > 0) {
6976 gint uri_idx = player->uri_info.uri_idx;
6978 if (uri_idx < num_of_list - 1)
6983 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6984 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6986 *uri = g_strdup(next_uri);
6990 return MM_ERROR_NONE;
6994 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6995 GstCaps *caps, gpointer data)
6997 mmplayer_t *player = (mmplayer_t *)data;
6998 const gchar *klass = NULL;
6999 const gchar *mime = NULL;
7000 gchar *caps_str = NULL;
7002 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7003 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7004 caps_str = gst_caps_to_string(caps);
7006 LOGW("unknown type of caps : %s from %s",
7007 caps_str, GST_ELEMENT_NAME(elem));
7009 MMPLAYER_FREEIF(caps_str);
7011 /* There is no available codec. */
7012 _mmplayer_update_not_supported_codec_info(player, klass, mime);
7016 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
7017 GstCaps *caps, gpointer data)
7019 mmplayer_t *player = (mmplayer_t *)data;
7020 const char *mime = NULL;
7021 gboolean ret = TRUE;
7023 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7024 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7026 if (g_str_has_prefix(mime, "audio")) {
7027 GstStructure *caps_structure = NULL;
7028 gint samplerate = 0;
7030 gchar *caps_str = NULL;
7032 caps_structure = gst_caps_get_structure(caps, 0);
7033 gst_structure_get_int(caps_structure, "rate", &samplerate);
7034 gst_structure_get_int(caps_structure, "channels", &channels);
7036 if ((channels > 0 && samplerate == 0)) {
7037 LOGD("exclude audio...");
7041 caps_str = gst_caps_to_string(caps);
7042 /* set it directly because not sent by TAG */
7043 if (g_strrstr(caps_str, "mobile-xmf"))
7044 mm_player_set_attribute((MMHandleType)player, NULL,
7045 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7047 MMPLAYER_FREEIF(caps_str);
7048 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7049 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7050 LOGD("video is already linked, allow the stream switch");
7053 LOGD("video is already linked");
7057 LOGD("found new stream");
7064 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7066 gboolean ret = FALSE;
7067 GDBusConnection *conn = NULL;
7069 GVariant *result = NULL;
7070 const gchar *dbus_device_type = NULL;
7071 const gchar *dbus_ret = NULL;
7074 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7076 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7081 result = g_dbus_connection_call_sync(conn,
7082 "org.pulseaudio.Server",
7083 "/org/pulseaudio/StreamManager",
7084 "org.pulseaudio.StreamManager",
7085 "GetCurrentMediaRoutingPath",
7086 g_variant_new("(s)", "out"),
7087 G_VARIANT_TYPE("(ss)"),
7088 G_DBUS_CALL_FLAGS_NONE,
7092 if (!result || err) {
7093 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7098 /* device type is listed in stream-map.json at mmfw-sysconf */
7099 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7101 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7102 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7105 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7106 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7107 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7108 LOGD("audio offload is supportable");
7114 LOGD("audio offload is not supportable");
7117 g_variant_unref(result);
7119 g_object_unref(conn);
7124 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7126 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7127 gint64 position = 0;
7129 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7130 player->pipeline && player->pipeline->mainbin);
7132 MMPLAYER_CMD_LOCK(player);
7133 current_state = MMPLAYER_CURRENT_STATE(player);
7135 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7136 LOGW("getting current position failed in paused");
7138 _mmplayer_unrealize((MMHandleType)player);
7139 _mmplayer_realize((MMHandleType)player);
7141 _mmplayer_set_position((MMHandleType)player, position);
7143 /* async not to be blocked in streaming case */
7144 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7146 _mmplayer_pause((MMHandleType)player);
7148 if (current_state == MM_PLAYER_STATE_PLAYING)
7149 _mmplayer_start((MMHandleType)player);
7150 MMPLAYER_CMD_UNLOCK(player);
7152 LOGD("rebuilding audio pipeline is completed.");
7155 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7157 mmplayer_t *player = (mmplayer_t *)user_data;
7158 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7159 gboolean is_supportable = FALSE;
7161 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7162 LOGW("failed to get device type");
7164 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7166 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7167 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7168 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7169 LOGD("ignore this dev connected info");
7173 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7174 if (player->build_audio_offload == is_supportable) {
7175 LOGD("keep current pipeline without re-building");
7179 /* rebuild pipeline */
7180 LOGD("re-build pipeline - offload: %d", is_supportable);
7181 player->build_audio_offload = FALSE;
7182 __mmplayer_rebuild_audio_pipeline(player);
7188 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7190 unsigned int id = 0;
7192 if (player->audio_device_cb_id != 0) {
7193 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7197 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7198 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7199 LOGD("added device connected cb (%u)", id);
7200 player->audio_device_cb_id = id;
7202 LOGW("failed to add device connected cb");
7209 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7211 mmplayer_t *player = (mmplayer_t *)hplayer;
7214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7215 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7217 *activated = player->build_audio_offload;
7219 LOGD("offload activated : %d", (int)*activated);
7222 return MM_ERROR_NONE;
7226 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7229 this function need to be updated according to the supported media format
7230 @see player->ini.audio_offload_media_format */
7232 if (__mmplayer_is_only_mp3_type(player->type_caps_str)) {
7233 LOGD("offload supportable media format type");
7241 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7243 gboolean ret = FALSE;
7244 GstElementFactory *factory = NULL;
7247 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7249 LOGD("current stream : %s, sink: %s", player->type_caps_str, player->ini.audio_offload_sink_element);
7250 if (!__mmplayer_is_offload_supported_type(player))
7253 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7254 LOGD("there is no audio offload sink");
7258 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7259 LOGW("there is no audio device type to support offload");
7263 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7265 LOGW("there is no installed audio offload sink element");
7268 gst_object_unref(factory);
7270 if (_mmplayer_acquire_hw_resource(player,
7271 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7272 LOGE("failed to acquire audio offload decoder resource");
7276 if (!__mmplayer_add_audio_device_connected_cb(player))
7279 if (!__mmplayer_is_audio_offload_device_type(player))
7282 LOGD("audio offload can be built");
7287 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7293 static GstAutoplugSelectResult
7294 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7296 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7297 int audio_offload = 0;
7299 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7300 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7302 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7303 LOGD("expose audio path to build offload output path");
7304 player->build_audio_offload = TRUE;
7305 /* update codec info */
7306 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7307 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7308 player->audiodec_linked = 1;
7310 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7314 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7315 And need to consider the multi-track audio content.
7316 There is no HW audio decoder in public. */
7318 /* set stream information */
7319 if (!player->audiodec_linked)
7320 _mmplayer_set_audio_attrs(player, caps);
7322 /* update codec info */
7323 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7324 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7325 player->audiodec_linked = 1;
7327 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7329 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7330 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7332 /* mark video decoder for acquire */
7333 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7334 LOGW("video decoder resource is already acquired, skip it.");
7335 ret = GST_AUTOPLUG_SELECT_SKIP;
7339 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7340 LOGE("failed to acquire video decoder resource");
7341 ret = GST_AUTOPLUG_SELECT_SKIP;
7344 player->interrupted_by_resource = FALSE;
7347 /* update codec info */
7348 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7349 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7350 player->videodec_linked = 1;
7358 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7359 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7361 #define DEFAULT_IDX 0xFFFF
7362 #define MIN_FACTORY_NUM 2
7363 mmplayer_t *player = (mmplayer_t *)data;
7364 GValueArray *new_factories = NULL;
7365 GValue val = { 0, };
7366 GstElementFactory *factory = NULL;
7367 const gchar *klass = NULL;
7368 gchar *factory_name = NULL;
7369 guint hw_dec_idx = DEFAULT_IDX;
7370 guint first_sw_dec_idx = DEFAULT_IDX;
7371 guint last_sw_dec_idx = DEFAULT_IDX;
7372 guint new_pos = DEFAULT_IDX;
7373 guint rm_pos = DEFAULT_IDX;
7374 int audio_codec_type;
7375 int video_codec_type;
7376 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7378 if (factories->n_values < MIN_FACTORY_NUM)
7381 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7382 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7385 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7387 for (int i = 0 ; i < factories->n_values ; i++) {
7388 gchar *hw_dec_info = NULL;
7389 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7391 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7393 LOGW("failed to get factory object");
7396 klass = gst_element_factory_get_klass(factory);
7397 factory_name = GST_OBJECT_NAME(factory);
7400 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7402 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7403 if (!player->need_audio_dec_sorting) {
7404 LOGD("sorting is not required");
7407 codec_type = audio_codec_type;
7408 hw_dec_info = player->ini.audiocodec_element_hw;
7409 sw_dec_info = player->ini.audiocodec_element_sw;
7410 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7411 if (!player->need_video_dec_sorting) {
7412 LOGD("sorting is not required");
7415 codec_type = video_codec_type;
7416 hw_dec_info = player->ini.videocodec_element_hw;
7417 sw_dec_info = player->ini.videocodec_element_sw;
7422 if (g_strrstr(factory_name, hw_dec_info)) {
7425 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7426 if (strstr(factory_name, sw_dec_info[j])) {
7427 last_sw_dec_idx = i;
7428 if (first_sw_dec_idx == DEFAULT_IDX) {
7429 first_sw_dec_idx = i;
7434 if (first_sw_dec_idx == DEFAULT_IDX)
7435 LOGW("unknown codec %s", factory_name);
7439 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7442 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7443 if (hw_dec_idx < first_sw_dec_idx)
7445 new_pos = first_sw_dec_idx;
7446 rm_pos = hw_dec_idx + 1;
7447 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7448 if (last_sw_dec_idx < hw_dec_idx)
7450 new_pos = last_sw_dec_idx + 1;
7451 rm_pos = hw_dec_idx;
7456 /* change position - insert H/W decoder according to the new position */
7457 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7459 LOGW("failed to get factory object");
7462 new_factories = g_value_array_copy(factories);
7463 g_value_init (&val, G_TYPE_OBJECT);
7464 g_value_set_object (&val, factory);
7465 g_value_array_insert(new_factories, new_pos, &val);
7466 g_value_unset (&val);
7467 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7469 for (int i = 0 ; i < new_factories->n_values ; i++) {
7470 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7472 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7473 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7475 LOGE("[Re-arranged] failed to get factory object");
7478 return new_factories;
7482 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7483 GstCaps *caps, GstElementFactory *factory, gpointer data)
7485 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7486 mmplayer_t *player = (mmplayer_t *)data;
7488 gchar *factory_name = NULL;
7489 gchar *caps_str = NULL;
7490 const gchar *klass = NULL;
7493 factory_name = GST_OBJECT_NAME(factory);
7494 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7495 caps_str = gst_caps_to_string(caps);
7497 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7499 /* store type string */
7500 if (player->type_caps_str == NULL) {
7501 player->type_caps_str = gst_caps_to_string(caps);
7502 __mmplayer_update_content_type_info(player);
7505 /* filtering exclude keyword */
7506 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7507 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7508 LOGW("skipping [%s] by exclude keyword [%s]",
7509 factory_name, player->ini.exclude_element_keyword[idx]);
7511 result = GST_AUTOPLUG_SELECT_SKIP;
7516 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7517 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7518 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7519 factory_name, player->ini.unsupported_codec_keyword[idx]);
7520 result = GST_AUTOPLUG_SELECT_SKIP;
7525 /* exclude webm format */
7526 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7527 * because webm format is not supportable.
7528 * If webm is disabled in "autoplug-continue", there is no state change
7529 * failure or error because the decodebin will expose the pad directly.
7530 * It make MSL invoke _prepare_async_callback.
7531 * So, we need to disable webm format in "autoplug-select" */
7532 if (caps_str && strstr(caps_str, "webm")) {
7533 LOGW("webm is not supported");
7534 result = GST_AUTOPLUG_SELECT_SKIP;
7538 /* check factory class for filtering */
7539 /* NOTE : msl don't need to use image plugins.
7540 * So, those plugins should be skipped for error handling.
7542 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7543 LOGD("skipping [%s] by not required", factory_name);
7544 result = GST_AUTOPLUG_SELECT_SKIP;
7548 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7549 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7550 // TO CHECK : subtitle if needed, add subparse exception.
7551 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7552 result = GST_AUTOPLUG_SELECT_SKIP;
7556 if (g_strrstr(factory_name, "mpegpsdemux")) {
7557 LOGD("skipping PS container - not support");
7558 result = GST_AUTOPLUG_SELECT_SKIP;
7562 if (g_strrstr(factory_name, "mssdemux"))
7563 player->smooth_streaming = TRUE;
7565 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7566 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7569 GstStructure *str = NULL;
7571 /* parsebin in adaptivedemux get error if there is no parser */
7572 if ((!g_strrstr(GST_ELEMENT_NAME(bin), "parsebin")) ||
7573 ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player)))) {
7574 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7576 /* don't make video because of not required */
7577 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7578 (!player->set_mode.video_export)) {
7579 LOGD("no need video decoding, expose pad");
7580 result = GST_AUTOPLUG_SELECT_EXPOSE;
7585 /* get w/h for omx state-tune */
7586 /* FIXME: deprecated? */
7587 str = gst_caps_get_structure(caps, 0);
7588 gst_structure_get_int(str, "width", &width);
7591 if (player->v_stream_caps) {
7592 gst_caps_unref(player->v_stream_caps);
7593 player->v_stream_caps = NULL;
7596 player->v_stream_caps = gst_caps_copy(caps);
7597 LOGD("take caps for video state tune");
7598 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7602 if (g_strrstr(klass, "Codec/Decoder")) {
7603 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7604 if (result != GST_AUTOPLUG_SELECT_TRY) {
7605 LOGW("skip add decoder");
7611 MMPLAYER_FREEIF(caps_str);
7617 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7620 int ret = MM_ERROR_NONE;
7621 mmplayer_t *player = (mmplayer_t *)data;
7622 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7623 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7624 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7627 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7629 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7631 if (MMPLAYER_USE_DECODEBIN(player))
7634 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7637 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7639 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7641 LOGD("remove videobin");
7642 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7643 GST_STATE_NULL, FALSE, timeout);
7644 if (ret != MM_ERROR_NONE) {
7645 LOGE("fail to change state of videobin to NULL");
7649 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7650 LOGE("failed to remove videobin");
7651 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7654 LOGD("remove concat");
7655 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7656 GST_STATE_NULL, FALSE, timeout);
7657 if (ret != MM_ERROR_NONE) {
7658 LOGE("fail to change state of concat to NULL");
7662 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7663 LOGE("failed to remove video concat");
7664 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7667 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7668 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7669 MMPLAYER_FREEIF(player->pipeline->videobin);
7671 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7672 if (ret != MM_ERROR_NONE)
7673 LOGE("failed to release overlay resources");
7675 player->videodec_linked = 0;
7677 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7682 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7684 mmplayer_t *player = (mmplayer_t *)data;
7687 MMPLAYER_RETURN_IF_FAIL(player);
7689 LOGD("got about to finish signal");
7691 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7692 LOGW("Fail to get cmd lock");
7696 if (!__mmplayer_verify_gapless_play_path(player)) {
7697 LOGD("decoding is finished.");
7698 if (MMPLAYER_USE_DECODEBIN(player)) {
7699 MMPLAYER_CMD_UNLOCK(player);
7704 if (MMPLAYER_USE_DECODEBIN(player)) {
7705 _mmplayer_set_reconfigure_state(player, TRUE);
7706 MMPLAYER_CMD_UNLOCK(player);
7707 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7708 __mmplayer_deactivate_old_path(player);
7710 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7711 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7712 MMPLAYER_CMD_UNLOCK(player);
7719 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7721 mmplayer_t *player = (mmplayer_t *)data;
7722 GstIterator *iter = NULL;
7723 GValue item = { 0, };
7725 gboolean done = FALSE;
7726 gboolean is_all_drained = TRUE;
7729 MMPLAYER_RETURN_IF_FAIL(player);
7731 LOGD("got drained signal");
7733 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7734 LOGW("Fail to get cmd lock");
7738 if (!__mmplayer_verify_gapless_play_path(player)) {
7739 LOGD("decoding is finished.");
7740 MMPLAYER_CMD_UNLOCK(player);
7744 _mmplayer_set_reconfigure_state(player, TRUE);
7745 MMPLAYER_CMD_UNLOCK(player);
7747 /* check decodebin src pads whether they received EOS or not */
7748 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7751 switch (gst_iterator_next(iter, &item)) {
7752 case GST_ITERATOR_OK:
7753 pad = g_value_get_object(&item);
7754 if (pad && !GST_PAD_IS_EOS(pad)) {
7755 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7756 is_all_drained = FALSE;
7759 g_value_reset(&item);
7761 case GST_ITERATOR_RESYNC:
7762 gst_iterator_resync(iter);
7764 case GST_ITERATOR_ERROR:
7765 case GST_ITERATOR_DONE:
7770 g_value_unset(&item);
7771 gst_iterator_free(iter);
7773 if (!is_all_drained) {
7774 LOGD("Wait util the all pads get EOS.");
7779 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7780 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7782 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7783 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7784 __mmplayer_deactivate_old_path(player);
7790 _mmplayer_gst_element_added(GstBin *bin, GstElement *element, gpointer data)
7792 mmplayer_t *player = (mmplayer_t *)data;
7793 const gchar *klass = NULL;
7794 gchar *factory_name = NULL;
7796 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7797 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7799 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7801 if (__mmplayer_add_dump_buffer_probe(player, element))
7802 LOGD("add buffer probe");
7804 if (g_strrstr(klass, "Decoder")) {
7805 if (g_strrstr(klass, "Audio")) {
7806 player->audio_decoders = g_list_append(player->audio_decoders,
7807 g_strdup(GST_ELEMENT_NAME(element)));
7809 /* update codec info */
7810 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7811 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7812 player->audiodec_linked = 1;
7813 } else if (g_strrstr(klass, "Video")) {
7814 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7815 /* update codec info */
7816 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7817 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7818 player->videodec_linked = 1;
7821 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7823 GstCaps *caps = NULL;
7824 GstStructure *str = NULL;
7825 const gchar *name = NULL;
7826 gboolean caps_ret = TRUE;
7828 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7829 if (caps_ret && str) {
7830 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7831 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7832 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7833 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7834 LOGD("Send SPS and PPS Insertion every IDR frame");
7838 gst_object_unref(GST_OBJECT(srcpad));
7842 } else if (g_strrstr(klass, "Demuxer")) {
7843 if (g_strrstr(klass, "Adaptive")) {
7844 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7845 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7847 MMPLAYER_FREEIF(player->type_caps_str);
7849 if (g_strrstr(factory_name, "hlsdemux")) {
7850 player->type_caps_str = g_strdup("application/x-hls");
7851 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7852 } else if (g_strrstr(factory_name, "dashdemux")) {
7853 player->type_caps_str = g_strdup("application/dash+xml");
7854 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7856 LOGE("not supported type");
7859 player->streamer->is_adaptive_streaming = TRUE;
7861 if (player->streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
7862 player->streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
7864 LOGD("max variant limit: %d, %d, %d, prebuffer time: %d ms",
7865 player->adaptive_info.limit.bandwidth,
7866 player->adaptive_info.limit.width,
7867 player->adaptive_info.limit.height,
7868 player->streamer->buffering_req.prebuffer_time);
7870 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7871 "max-bitrate", player->adaptive_info.limit.bandwidth,
7872 "max-video-width", player->adaptive_info.limit.width,
7873 "max-video-height", player->adaptive_info.limit.height,
7874 "low-watermark-time", (guint64)(player->streamer->buffering_req.prebuffer_time * GST_MSECOND),
7878 LOGD("plugged element is demuxer. take it");
7880 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7881 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7883 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7884 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7885 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7888 if (g_strrstr(factory_name, "mpegaudioparse")) {
7889 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7890 (__mmplayer_is_only_mp3_type(player->type_caps_str))) {
7891 LOGD("[mpegaudioparse] set streaming pull mode.");
7892 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7894 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7895 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7897 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7899 /* set mq unlinked cache size to avoid not-linked error */
7900 gboolean sync_by_running_time = FALSE;
7901 g_object_get(G_OBJECT(element), "sync-by-running-time", &sync_by_running_time, NULL);
7902 if (sync_by_running_time)
7903 g_object_set(G_OBJECT(element), "unlinked-cache-time", MQ_UNLINKED_CACHE_TIME, NULL);
7905 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7906 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7908 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7909 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7910 _mm_player_streaming_set_multiqueue(player->streamer, element);
7911 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7919 __mmplayer_release_misc(mmplayer_t *player)
7922 bool cur_mode = player->set_mode.rich_audio;
7925 MMPLAYER_RETURN_IF_FAIL(player);
7927 player->sent_bos = FALSE;
7928 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7930 player->seek_state = MMPLAYER_SEEK_NONE;
7932 player->total_bitrate = 0;
7933 player->total_maximum_bitrate = 0;
7935 player->not_found_demuxer = 0;
7937 player->last_position = 0;
7938 player->duration = 0;
7939 player->http_content_size = 0;
7940 player->not_supported_codec = MISSING_PLUGIN_NONE;
7941 player->can_support_codec = FOUND_PLUGIN_NONE;
7942 player->pending_seek.is_pending = false;
7943 player->pending_seek.pos = 0;
7944 player->msg_posted = FALSE;
7945 player->has_many_types = FALSE;
7946 player->is_subtitle_force_drop = FALSE;
7947 player->play_subtitle = FALSE;
7948 player->adjust_subtitle_pos = 0;
7949 player->has_closed_caption = FALSE;
7950 player->set_mode.video_export = false;
7951 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7952 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7954 player->set_mode.rich_audio = cur_mode;
7956 if (player->audio_device_cb_id > 0 &&
7957 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7958 LOGW("failed to remove audio device_connected_callback");
7959 player->audio_device_cb_id = 0;
7961 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7962 player->bitrate[i] = 0;
7963 player->maximum_bitrate[i] = 0;
7966 /* free memory related to audio effect */
7967 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7969 if (player->adaptive_info.var_list) {
7970 g_list_free_full(player->adaptive_info.var_list, g_free);
7971 player->adaptive_info.var_list = NULL;
7974 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7975 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7976 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7978 /* Reset video360 settings to their defaults in case if the pipeline is to be
7981 player->video360_metadata.is_spherical = -1;
7982 player->is_openal_plugin_used = FALSE;
7984 player->is_content_spherical = FALSE;
7985 player->is_video360_enabled = TRUE;
7986 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7987 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7988 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7989 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7990 player->video360_zoom = 1.0f;
7991 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7992 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7994 player->sound.rg_enable = false;
7996 __mmplayer_initialize_video_roi(player);
8001 __mmplayer_release_misc_post(mmplayer_t *player)
8003 gchar *original_uri = NULL;
8006 /* player->pipeline is already released before. */
8007 MMPLAYER_RETURN_IF_FAIL(player);
8009 player->video_decoded_cb = NULL;
8010 player->video_decoded_cb_user_param = NULL;
8011 player->video_stream_prerolled = false;
8013 player->audio_decoded_cb = NULL;
8014 player->audio_decoded_cb_user_param = NULL;
8015 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
8017 player->audio_stream_changed_cb = NULL;
8018 player->audio_stream_changed_cb_user_param = NULL;
8020 mm_player_set_attribute((MMHandleType)player, NULL,
8021 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
8023 /* clean found audio decoders */
8024 if (player->audio_decoders) {
8025 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
8026 player->audio_decoders = NULL;
8029 /* clean the uri list except original uri */
8030 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
8032 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8033 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
8034 g_list_free_full(tmp, (GDestroyNotify)g_free);
8037 LOGW("failed to get original uri info");
8039 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
8040 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
8041 MMPLAYER_FREEIF(original_uri);
8044 /* clear the audio stream buffer list */
8045 _mmplayer_audio_stream_clear_buffer(player, FALSE);
8047 /* clear the video stream bo list */
8048 __mmplayer_video_stream_destroy_bo_list(player);
8049 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8051 if (player->profile.input_mem.buf) {
8052 free(player->profile.input_mem.buf);
8053 player->profile.input_mem.buf = NULL;
8055 player->profile.input_mem.len = 0;
8056 player->profile.input_mem.offset = 0;
8058 player->uri_info.uri_idx = 0;
8063 __mmplayer_check_subtitle(mmplayer_t *player)
8065 MMHandleType attrs = 0;
8066 char *subtitle_uri = NULL;
8070 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8072 /* get subtitle attribute */
8073 attrs = MMPLAYER_GET_ATTRS(player);
8077 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8078 if (!subtitle_uri || !strlen(subtitle_uri))
8081 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8082 player->is_external_subtitle_present = TRUE;
8090 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8092 MMPLAYER_RETURN_IF_FAIL(player);
8094 if (player->eos_timer) {
8095 LOGD("cancel eos timer");
8096 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8097 player->eos_timer = 0;
8104 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8108 MMPLAYER_RETURN_IF_FAIL(player);
8109 MMPLAYER_RETURN_IF_FAIL(sink);
8112 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8114 player->sink_elements = g_list_append(player->sink_elements, sink);
8120 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8124 MMPLAYER_RETURN_IF_FAIL(player);
8125 MMPLAYER_RETURN_IF_FAIL(sink);
8127 player->sink_elements = g_list_remove(player->sink_elements, sink);
8133 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8134 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8136 mmplayer_signal_item_t *item = NULL;
8139 MMPLAYER_RETURN_IF_FAIL(player);
8141 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8142 LOGE("invalid signal type [%d]", type);
8146 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8148 LOGE("cannot connect signal [%s]", signal);
8153 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8154 player->signals[type] = g_list_append(player->signals[type], item);
8160 /* NOTE : be careful with calling this api. please refer to below glib comment
8161 * glib comment : Note that there is a bug in GObject that makes this function much
8162 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8163 * will no longer be called, but, the signal handler is not currently disconnected.
8164 * If the instance is itself being freed at the same time than this doesn't matter,
8165 * since the signal will automatically be removed, but if instance persists,
8166 * then the signal handler will leak. You should not remove the signal yourself
8167 * because in a future versions of GObject, the handler will automatically be
8170 * It's possible to work around this problem in a way that will continue to work
8171 * with future versions of GObject by checking that the signal handler is still
8172 * connected before disconnected it:
8174 * if (g_signal_handler_is_connected(instance, id))
8175 * g_signal_handler_disconnect(instance, id);
8178 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8180 GList *sig_list = NULL;
8181 mmplayer_signal_item_t *item = NULL;
8185 MMPLAYER_RETURN_IF_FAIL(player);
8187 LOGD("release signals type : %d", type);
8189 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8190 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8191 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8192 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8193 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8194 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8198 sig_list = player->signals[type];
8200 for (; sig_list; sig_list = sig_list->next) {
8201 item = sig_list->data;
8203 if (item && item->obj) {
8204 if (g_signal_handler_is_connected(item->obj, item->sig))
8205 g_signal_handler_disconnect(item->obj, item->sig);
8208 MMPLAYER_FREEIF(item);
8211 g_list_free(player->signals[type]);
8212 player->signals[type] = NULL;
8220 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8222 mmplayer_t *player = 0;
8223 int prev_display_surface_type = 0;
8227 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8229 player = MM_PLAYER_CAST(handle);
8231 /* check video sinkbin is created */
8232 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8233 LOGW("Videosink is already created");
8234 return MM_ERROR_NONE;
8237 LOGD("videosink element is not yet ready");
8239 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8240 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8242 return MM_ERROR_INVALID_ARGUMENT;
8245 /* load previous attributes */
8246 if (player->attrs) {
8247 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8248 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8249 if (prev_display_surface_type == surface_type) {
8250 LOGD("incoming display surface type is same as previous one, do nothing..");
8252 return MM_ERROR_NONE;
8255 LOGE("failed to load attributes");
8257 return MM_ERROR_PLAYER_INTERNAL;
8260 /* videobin is not created yet, so we just set attributes related to display surface */
8261 LOGD("store display attribute for given surface type(%d)", surface_type);
8262 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8263 "display_overlay", wl_surface_id, NULL);
8266 return MM_ERROR_NONE;
8269 /* Note : if silent is true, then subtitle would not be displayed. :*/
8271 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8273 mmplayer_t *player = (mmplayer_t *)hplayer;
8277 /* check player handle */
8278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8280 player->set_mode.subtitle_off = silent;
8282 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8286 return MM_ERROR_NONE;
8290 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8292 mmplayer_gst_element_t *mainbin = NULL;
8293 mmplayer_gst_element_t *textbin = NULL;
8294 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8295 GstState current_state = GST_STATE_VOID_PENDING;
8296 GstState element_state = GST_STATE_VOID_PENDING;
8297 GstState element_pending_state = GST_STATE_VOID_PENDING;
8299 GstEvent *event = NULL;
8300 int result = MM_ERROR_NONE;
8302 GstClock *curr_clock = NULL;
8303 GstClockTime base_time, start_time, curr_time;
8308 /* check player handle */
8309 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8311 player->pipeline->mainbin &&
8312 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8314 mainbin = player->pipeline->mainbin;
8315 textbin = player->pipeline->textbin;
8317 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8319 // sync clock with current pipeline
8320 curr_clock = gst_element_get_clock(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8321 curr_time = gst_clock_get_time(curr_clock);
8323 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8324 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8326 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8327 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8329 if (current_state > GST_STATE_READY) {
8330 // sync state with current pipeline
8331 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8332 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8333 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8335 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8336 if (GST_STATE_CHANGE_FAILURE == ret) {
8337 LOGE("fail to state change.");
8338 result = MM_ERROR_PLAYER_INTERNAL;
8340 gst_object_unref(curr_clock);
8344 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8345 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8348 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8349 gst_object_unref(curr_clock);
8352 // seek to current position
8353 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8354 result = MM_ERROR_PLAYER_INVALID_STATE;
8355 LOGE("gst_element_query_position failed, invalid state");
8359 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8360 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);
8362 _mmplayer_gst_send_event_to_sink(player, event);
8364 result = MM_ERROR_PLAYER_INTERNAL;
8365 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8369 /* sync state with current pipeline */
8370 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8371 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8372 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8374 return MM_ERROR_NONE;
8377 /* release text pipeline resource */
8378 player->textsink_linked = 0;
8380 /* release signal */
8381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8383 /* release textbin with it's children */
8384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8385 MMPLAYER_FREEIF(player->pipeline->textbin);
8386 player->pipeline->textbin = NULL;
8388 /* release subtitle elem */
8389 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8390 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8396 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8398 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8399 GstState current_state = GST_STATE_VOID_PENDING;
8401 MMHandleType attrs = 0;
8402 mmplayer_gst_element_t *mainbin = NULL;
8403 mmplayer_gst_element_t *textbin = NULL;
8405 gchar *subtitle_uri = NULL;
8406 int result = MM_ERROR_NONE;
8407 const gchar *charset = NULL;
8411 /* check player handle */
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8414 player->pipeline->mainbin &&
8415 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8416 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8418 mainbin = player->pipeline->mainbin;
8419 textbin = player->pipeline->textbin;
8421 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8422 if (current_state < GST_STATE_READY) {
8423 result = MM_ERROR_PLAYER_INVALID_STATE;
8424 LOGE("Pipeline is not in proper state");
8428 attrs = MMPLAYER_GET_ATTRS(player);
8430 LOGE("cannot get content attribute");
8431 result = MM_ERROR_PLAYER_INTERNAL;
8435 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8436 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8437 LOGE("subtitle uri is not proper filepath");
8438 result = MM_ERROR_PLAYER_INVALID_URI;
8442 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8443 LOGE("failed to get storage info of subtitle path");
8444 result = MM_ERROR_PLAYER_INVALID_URI;
8448 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8449 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8451 if (!strcmp(filepath, subtitle_uri)) {
8452 LOGD("subtitle path is not changed");
8455 if (mm_player_set_attribute((MMHandleType)player, NULL,
8456 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8457 LOGE("failed to set attribute");
8462 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8463 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8464 player->subtitle_language_list = NULL;
8465 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8467 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8468 if (ret != GST_STATE_CHANGE_SUCCESS) {
8469 LOGE("failed to change state of textbin to READY");
8470 result = MM_ERROR_PLAYER_INTERNAL;
8474 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8475 if (ret != GST_STATE_CHANGE_SUCCESS) {
8476 LOGE("failed to change state of subparse to READY");
8477 result = MM_ERROR_PLAYER_INTERNAL;
8481 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8482 if (ret != GST_STATE_CHANGE_SUCCESS) {
8483 LOGE("failed to change state of filesrc to READY");
8484 result = MM_ERROR_PLAYER_INTERNAL;
8488 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8490 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8492 charset = _mmplayer_get_charset(filepath);
8494 LOGD("detected charset is %s", charset);
8495 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8498 result = _mmplayer_sync_subtitle_pipeline(player);
8505 /* API to switch between external subtitles */
8507 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8509 int result = MM_ERROR_NONE;
8510 mmplayer_t *player = (mmplayer_t *)hplayer;
8515 /* check player handle */
8516 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8518 /* filepath can be null in idle state */
8520 /* check file path */
8521 if ((path = strstr(filepath, "file://")))
8522 result = _mmplayer_exist_file_path(path + 7);
8524 result = _mmplayer_exist_file_path(filepath);
8526 if (result != MM_ERROR_NONE) {
8527 LOGE("invalid subtitle path 0x%X", result);
8528 return result; /* file not found or permission denied */
8532 if (!player->pipeline) {
8534 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8535 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8536 LOGE("failed to set attribute");
8537 return MM_ERROR_PLAYER_INTERNAL;
8540 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8541 /* check filepath */
8542 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8544 if (!__mmplayer_check_subtitle(player)) {
8545 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8546 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8547 LOGE("failed to set attribute");
8548 return MM_ERROR_PLAYER_INTERNAL;
8551 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8552 LOGE("fail to create text pipeline");
8553 return MM_ERROR_PLAYER_INTERNAL;
8556 result = _mmplayer_sync_subtitle_pipeline(player);
8558 result = __mmplayer_change_external_subtitle_language(player, filepath);
8561 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8562 player->is_external_subtitle_added_now = TRUE;
8564 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8565 if (!player->subtitle_language_list) {
8566 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8567 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8568 LOGW("subtitle language list is not updated yet");
8570 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8578 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8580 guint active_idx = 0;
8581 GstStream *stream = NULL;
8582 GList *streams = NULL;
8583 GstCaps *caps = NULL;
8586 LOGD("Switching Streams... type: %d, index: %d", type, index);
8588 player->track[type].active_track_index = index;
8590 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8591 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8592 LOGD("track type:%d, total: %d, active: %d", i,
8593 player->track[i].total_track_num, player->track[i].active_track_index);
8594 if (player->track[i].total_track_num > 0 &&
8595 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8596 active_idx = player->track[i].active_track_index;
8597 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8598 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8599 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8601 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8602 caps = gst_stream_get_caps(stream);
8604 _mmplayer_set_audio_attrs(player, caps);
8605 gst_caps_unref(caps);
8612 LOGD("send select stream event");
8613 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8614 gst_event_new_select_streams(streams));
8615 g_list_free(streams);
8618 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8619 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8620 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8622 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8623 pos_nsec = player->last_position;
8625 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8627 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8628 player->playback_rate, GST_FORMAT_TIME,
8629 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8630 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8631 LOGW("failed to seek");
8632 return MM_ERROR_PLAYER_INTERNAL;
8637 return MM_ERROR_NONE;
8641 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8643 int result = MM_ERROR_NONE;
8644 gchar *change_pad_name = NULL;
8645 GstPad *sinkpad = NULL;
8646 mmplayer_gst_element_t *mainbin = NULL;
8647 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8648 GstCaps *caps = NULL;
8649 gint total_track_num = 0;
8653 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8654 MM_ERROR_PLAYER_NOT_INITIALIZED);
8656 LOGD("Change Track(%d) to %d", type, index);
8658 mainbin = player->pipeline->mainbin;
8660 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8661 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8662 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8663 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8665 /* Changing Video Track is not supported. */
8666 LOGE("Track Type Error");
8670 if (mainbin[elem_idx].gst == NULL) {
8671 result = MM_ERROR_PLAYER_NO_OP;
8672 LOGD("Req track doesn't exist");
8676 total_track_num = player->track[type].total_track_num;
8677 if (total_track_num <= 0) {
8678 result = MM_ERROR_PLAYER_NO_OP;
8679 LOGD("Language list is not available");
8683 if ((index < 0) || (index >= total_track_num)) {
8684 result = MM_ERROR_INVALID_ARGUMENT;
8685 LOGD("Not a proper index : %d", index);
8689 /*To get the new pad from the selector*/
8690 change_pad_name = g_strdup_printf("sink_%u", index);
8691 if (change_pad_name == NULL) {
8692 result = MM_ERROR_PLAYER_INTERNAL;
8693 LOGD("Pad does not exists");
8697 LOGD("new active pad name: %s", change_pad_name);
8699 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8700 if (sinkpad == NULL) {
8701 LOGD("sinkpad is NULL");
8702 result = MM_ERROR_PLAYER_INTERNAL;
8706 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8707 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8709 caps = gst_pad_get_current_caps(sinkpad);
8710 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8713 gst_object_unref(sinkpad);
8715 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8716 _mmplayer_set_audio_attrs(player, caps);
8719 gst_caps_unref(caps);
8722 MMPLAYER_FREEIF(change_pad_name);
8727 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8729 int result = MM_ERROR_NONE;
8730 mmplayer_t *player = NULL;
8731 mmplayer_gst_element_t *mainbin = NULL;
8733 gint current_active_index = 0;
8735 GstState current_state = GST_STATE_VOID_PENDING;
8740 player = (mmplayer_t *)hplayer;
8741 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8742 MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_PLAYER_NOT_INITIALIZED);
8744 if (!player->pipeline) {
8745 LOGE("Track %d pre setting -> %d", type, index);
8747 player->track[type].active_track_index = index;
8751 mainbin = player->pipeline->mainbin;
8753 current_active_index = player->track[type].active_track_index;
8755 /*If index is same as running index no need to change the pad*/
8756 if (current_active_index == index)
8759 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8760 result = MM_ERROR_PLAYER_INVALID_STATE;
8764 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8765 if (current_state < GST_STATE_PAUSED) {
8766 result = MM_ERROR_PLAYER_INVALID_STATE;
8767 LOGW("Pipeline not in proper state");
8771 if (MMPLAYER_USE_DECODEBIN(player))
8772 result = __mmplayer_change_selector_pad(player, type, index);
8774 result = __mmplayer_switch_stream(player, type, index);
8776 if (result != MM_ERROR_NONE) {
8777 LOGE("failed to change track");
8781 player->track[type].active_track_index = index;
8783 if (MMPLAYER_USE_DECODEBIN(player)) {
8784 GstEvent *event = NULL;
8785 if (current_state == GST_STATE_PLAYING) {
8786 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8787 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8788 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8790 _mmplayer_gst_send_event_to_sink(player, event);
8792 result = MM_ERROR_PLAYER_INTERNAL;
8803 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8805 mmplayer_t *player = (mmplayer_t *)hplayer;
8809 /* check player handle */
8810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 *silent = player->set_mode.subtitle_off;
8814 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8818 return MM_ERROR_NONE;
8822 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8824 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8825 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8827 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8828 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8832 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8833 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8834 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8835 mmplayer_dump_t *dump_s;
8836 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8837 if (dump_s == NULL) {
8838 LOGE("malloc fail");
8842 dump_s->dump_element_file = NULL;
8843 dump_s->dump_pad = NULL;
8844 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8846 if (dump_s->dump_pad) {
8847 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8848 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]);
8849 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8850 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);
8851 /* add list for removed buffer probe and close FILE */
8852 player->dump_list = g_list_append(player->dump_list, dump_s);
8853 LOGD("%s sink pad added buffer probe for dump", factory_name);
8856 MMPLAYER_FREEIF(dump_s);
8857 LOGE("failed to get %s sink pad added", factory_name);
8864 static GstPadProbeReturn
8865 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8867 FILE *dump_data = (FILE *)u_data;
8869 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8870 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8872 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8874 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8876 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8878 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8880 gst_buffer_unmap(buffer, &probe_info);
8882 return GST_PAD_PROBE_OK;
8886 __mmplayer_release_dump_list(GList *dump_list)
8888 GList *d_list = dump_list;
8893 for (; d_list; d_list = g_list_next(d_list)) {
8894 mmplayer_dump_t *dump_s = d_list->data;
8895 if (dump_s->dump_pad) {
8896 if (dump_s->probe_handle_id)
8897 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8898 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8900 if (dump_s->dump_element_file) {
8901 fclose(dump_s->dump_element_file);
8902 dump_s->dump_element_file = NULL;
8904 MMPLAYER_FREEIF(dump_s);
8906 g_list_free(dump_list);
8911 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8913 mmplayer_t *player = (mmplayer_t *)hplayer;
8917 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8918 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8920 *exist = (bool)player->has_closed_caption;
8924 return MM_ERROR_NONE;
8928 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8933 LOGD("unref internal gst buffer %p", buffer);
8935 gst_buffer_unref((GstBuffer *)buffer);
8942 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8944 mmplayer_t *player = (mmplayer_t *)hplayer;
8948 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8949 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8951 if (MMPLAYER_IS_STREAMING(player))
8952 *timeout = (int)player->ini.live_state_change_timeout;
8954 *timeout = (int)player->ini.localplayback_state_change_timeout;
8956 LOGD("timeout = %d", *timeout);
8959 return MM_ERROR_NONE;
8963 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8967 MMPLAYER_RETURN_IF_FAIL(player);
8969 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8971 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8972 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8973 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8974 player->storage_info[i].id = -1;
8975 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8977 if (path_type != MMPLAYER_PATH_MAX)
8986 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8988 int ret = MM_ERROR_NONE;
8989 mmplayer_t *player = (mmplayer_t *)hplayer;
8990 MMMessageParamType msg_param = {0, };
8993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8995 LOGW("state changed storage %d:%d", id, state);
8997 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8998 return MM_ERROR_NONE;
9000 /* FIXME: text path should be handled separately. */
9001 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
9002 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9003 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
9004 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9005 LOGW("external storage is removed");
9007 if (player->msg_posted == FALSE) {
9008 memset(&msg_param, 0, sizeof(MMMessageParamType));
9009 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9010 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9011 player->msg_posted = TRUE;
9014 /* unrealize the player */
9015 ret = _mmplayer_unrealize(hplayer);
9016 if (ret != MM_ERROR_NONE)
9017 LOGE("failed to unrealize");
9025 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9027 int ret = MM_ERROR_NONE;
9028 mmplayer_t *player = (mmplayer_t *)hplayer;
9029 int idx = 0, total = 0;
9030 gchar *result = NULL, *tmp = NULL;
9033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9034 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9036 total = *num = g_list_length(player->adaptive_info.var_list);
9038 LOGW("There is no stream variant info.");
9042 result = g_strdup("");
9043 for (idx = 0 ; idx < total ; idx++) {
9044 stream_variant_t *v_data = NULL;
9045 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9048 gchar data[64] = {0};
9049 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9051 tmp = g_strconcat(result, data, NULL);
9055 LOGW("There is no variant data in %d", idx);
9060 *var_info = (char *)result;
9062 LOGD("variant info %d:%s", *num, *var_info);
9068 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9070 int ret = MM_ERROR_NONE;
9071 mmplayer_t *player = (mmplayer_t *)hplayer;
9074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9078 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9079 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9080 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9082 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9083 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9084 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9085 "max-bitrate", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9087 /* FIXME: seek to current position for applying new variant limitation */
9096 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9098 int ret = MM_ERROR_NONE;
9099 mmplayer_t *player = (mmplayer_t *)hplayer;
9102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9103 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9105 *bandwidth = player->adaptive_info.limit.bandwidth;
9106 *width = player->adaptive_info.limit.width;
9107 *height = player->adaptive_info.limit.height;
9109 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9116 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9118 int ret = MM_ERROR_NONE;
9119 mmplayer_t *player = (mmplayer_t *)hplayer;
9122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9123 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9124 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9126 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9128 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9129 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9130 else /* live case */
9131 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9133 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9140 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9142 #define IDX_FIRST_SW_CODEC 0
9143 mmplayer_t *player = (mmplayer_t *)hplayer;
9144 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9145 const char *attr_name = NULL;
9146 const char *default_type = NULL;
9147 const char *element_hw = NULL;
9148 const char *element_sw = NULL;
9151 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9153 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9155 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9156 switch (stream_type) {
9157 case MM_PLAYER_STREAM_TYPE_AUDIO:
9158 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9159 default_type = player->ini.audiocodec_default_type;
9160 element_hw = player->ini.audiocodec_element_hw;
9161 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9163 case MM_PLAYER_STREAM_TYPE_VIDEO:
9164 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9165 default_type = player->ini.videocodec_default_type;
9166 element_hw = player->ini.videocodec_element_hw;
9167 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9170 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9171 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9175 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9177 if (!strcmp(default_type, "sw"))
9178 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9180 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9182 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9183 codec_type = default_codec_type;
9185 /* to support codec selection, codec info have to be added in ini file.
9186 in case of hw codec is selected, filter elements should be applied
9187 depending on the hw capabilities. */
9188 if (codec_type != default_codec_type) {
9189 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9190 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9191 LOGE("There is no codec for type %d", codec_type);
9192 return MM_ERROR_PLAYER_NO_OP;
9195 LOGD("sorting is required");
9196 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9197 player->need_audio_dec_sorting = TRUE;
9199 player->need_video_dec_sorting = TRUE;
9202 LOGD("update %s codec_type to %d", attr_name, codec_type);
9203 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9206 return MM_ERROR_NONE;
9210 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9212 mmplayer_t *player = (mmplayer_t *)hplayer;
9213 GstElement *rg_vol_element = NULL;
9217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9219 player->sound.rg_enable = enabled;
9221 /* just hold rgvolume enable value if pipeline is not ready */
9222 if (!player->pipeline || !player->pipeline->audiobin) {
9223 LOGD("pipeline is not ready. holding rgvolume enable value");
9224 return MM_ERROR_NONE;
9227 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9229 if (!rg_vol_element) {
9230 LOGD("rgvolume element is not created");
9231 return MM_ERROR_PLAYER_INTERNAL;
9235 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9237 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9241 return MM_ERROR_NONE;
9245 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9247 mmplayer_t *player = (mmplayer_t *)hplayer;
9248 GstElement *rg_vol_element = NULL;
9249 gboolean enable = FALSE;
9253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9254 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9256 /* just hold enable_rg value if pipeline is not ready */
9257 if (!player->pipeline || !player->pipeline->audiobin) {
9258 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9259 *enabled = player->sound.rg_enable;
9260 return MM_ERROR_NONE;
9263 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9265 if (!rg_vol_element) {
9266 LOGD("rgvolume element is not created");
9267 return MM_ERROR_PLAYER_INTERNAL;
9270 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9271 *enabled = (bool)enable;
9275 return MM_ERROR_NONE;
9279 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9281 mmplayer_t *player = (mmplayer_t *)hplayer;
9282 MMHandleType attrs = 0;
9284 int ret = MM_ERROR_NONE;
9288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9290 attrs = MMPLAYER_GET_ATTRS(player);
9291 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9293 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9295 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9296 return MM_ERROR_PLAYER_INTERNAL;
9299 player->video_roi.scale_x = scale_x;
9300 player->video_roi.scale_y = scale_y;
9301 player->video_roi.scale_width = scale_width;
9302 player->video_roi.scale_height = scale_height;
9304 /* check video sinkbin is created */
9305 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9306 return MM_ERROR_NONE;
9308 if (!gst_video_overlay_set_video_roi_area(
9309 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9310 scale_x, scale_y, scale_width, scale_height))
9311 ret = MM_ERROR_PLAYER_INTERNAL;
9313 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9314 scale_x, scale_y, scale_width, scale_height);
9322 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9324 mmplayer_t *player = (mmplayer_t *)hplayer;
9325 int ret = MM_ERROR_NONE;
9329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9330 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9332 *scale_x = player->video_roi.scale_x;
9333 *scale_y = player->video_roi.scale_y;
9334 *scale_width = player->video_roi.scale_width;
9335 *scale_height = player->video_roi.scale_height;
9337 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9338 *scale_x, *scale_y, *scale_width, *scale_height);
9344 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9346 mmplayer_t *player = (mmplayer_t *)hplayer;
9350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9352 player->client_pid = pid;
9354 LOGD("client pid[%d] %p", pid, player);
9358 return MM_ERROR_NONE;
9362 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9364 mmplayer_t *player = (mmplayer_t *)hplayer;
9365 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9366 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9371 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9374 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9376 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9378 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9379 return MM_ERROR_NONE;
9381 /* in case of audio codec default type is HW */
9383 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9384 if (player->ini.support_audio_effect)
9385 return MM_ERROR_NONE;
9386 elem_id = MMPLAYER_A_FILTER;
9388 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9389 if (player->ini.support_replaygain_control)
9390 return MM_ERROR_NONE;
9391 elem_id = MMPLAYER_A_RGVOL;
9393 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9394 if (player->ini.support_pitch_control)
9395 return MM_ERROR_NONE;
9396 elem_id = MMPLAYER_A_PITCH;
9398 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9399 if (player->ini.support_audio_effect)
9400 return MM_ERROR_NONE;
9402 /* default case handling is not required */
9405 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9406 LOGW("audio control option [%d] is not available", opt);
9409 /* setting pcm exporting option is allowed before READY state */
9410 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9411 return MM_ERROR_PLAYER_INVALID_STATE;
9413 /* check whether the audio filter exist or not after READY state,
9414 because the sw codec could be added during auto-plugging in some cases */
9415 if (!player->pipeline ||
9416 !player->pipeline->audiobin ||
9417 !player->pipeline->audiobin[elem_id].gst) {
9418 LOGW("there is no audio elem [%d]", elem_id);
9423 LOGD("audio control opt %d, available %d", opt, *available);
9427 return MM_ERROR_NONE;
9431 __mmplayer_update_duration_value(mmplayer_t *player)
9433 gboolean ret = FALSE;
9434 gint64 dur_nsec = 0;
9435 LOGD("try to update duration");
9437 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9438 player->duration = dur_nsec;
9439 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9443 if (player->duration < 0) {
9444 LOGW("duration is Non-Initialized !!!");
9445 player->duration = 0;
9448 /* update streaming service type */
9449 player->streaming_type = _mmplayer_get_stream_service_type(player);
9451 /* check duration is OK */
9452 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9453 /* FIXIT : find another way to get duration here. */
9454 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9460 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9462 /* update audio params
9463 NOTE : We need original audio params and it can be only obtained from src pad of audio
9464 decoder. Below code only valid when we are not using 'resampler' just before
9465 'audioconverter'. */
9466 GstCaps *caps_a = NULL;
9468 gint samplerate = 0, channels = 0;
9469 GstStructure *p = NULL;
9470 GstElement *aconv = NULL;
9472 LOGD("try to update audio attrs");
9474 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9476 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9477 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9478 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9479 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9481 LOGE("there is no audio converter");
9485 pad = gst_element_get_static_pad(aconv, "sink");
9488 LOGW("failed to get pad from audio converter");
9492 caps_a = gst_pad_get_current_caps(pad);
9494 LOGW("not ready to get audio caps");
9495 gst_object_unref(pad);
9499 p = gst_caps_get_structure(caps_a, 0);
9500 gst_structure_get_int(p, "rate", &samplerate);
9501 gst_structure_get_int(p, "channels", &channels);
9503 mm_player_set_attribute((MMHandleType)player, NULL,
9504 "content_audio_samplerate", samplerate,
9505 "content_audio_channels", channels, NULL);
9507 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9509 gst_caps_unref(caps_a);
9510 gst_object_unref(pad);
9516 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9518 LOGD("try to update video attrs");
9520 GstCaps *caps_v = NULL;
9524 GstStructure *p = NULL;
9526 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9527 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9529 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9531 LOGD("no videosink sink pad");
9535 caps_v = gst_pad_get_current_caps(pad);
9536 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9537 if (!caps_v && player->v_stream_caps) {
9538 caps_v = player->v_stream_caps;
9539 gst_caps_ref(caps_v);
9543 LOGD("no negotiated caps from videosink");
9544 gst_object_unref(pad);
9548 p = gst_caps_get_structure(caps_v, 0);
9549 gst_structure_get_int(p, "width", &width);
9550 gst_structure_get_int(p, "height", &height);
9552 mm_player_set_attribute((MMHandleType)player, NULL,
9553 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9555 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9557 SECURE_LOGD("width : %d height : %d", width, height);
9559 gst_caps_unref(caps_v);
9560 gst_object_unref(pad);
9563 mm_player_set_attribute((MMHandleType)player, NULL,
9564 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9565 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9572 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9574 gboolean ret = FALSE;
9575 guint64 data_size = 0;
9579 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9580 if (!player->duration)
9583 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9584 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9585 if (stat(path, &sb) == 0)
9586 data_size = (guint64)sb.st_size;
9588 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9589 data_size = player->http_content_size;
9592 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9595 guint64 bitrate = 0;
9596 guint64 msec_dur = 0;
9598 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9600 bitrate = data_size * 8 * 1000 / msec_dur;
9601 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9602 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9603 mm_player_set_attribute((MMHandleType)player, NULL,
9604 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9607 LOGD("player duration is less than 0");
9611 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9612 if (player->total_bitrate) {
9613 mm_player_set_attribute((MMHandleType)player, NULL,
9614 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9623 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9625 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9626 data->uri_type = uri_type;
9630 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9632 int ret = MM_ERROR_PLAYER_INVALID_URI;
9634 char *buffer = NULL;
9635 char *seperator = strchr(path, ',');
9636 char ext[100] = {0,}, size[100] = {0,};
9639 if ((buffer = strstr(path, "ext="))) {
9640 buffer += strlen("ext=");
9642 if (strlen(buffer)) {
9643 strncpy(ext, buffer, 99);
9645 if ((seperator = strchr(ext, ','))
9646 || (seperator = strchr(ext, ' '))
9647 || (seperator = strchr(ext, '\0'))) {
9648 seperator[0] = '\0';
9653 if ((buffer = strstr(path, "size="))) {
9654 buffer += strlen("size=");
9656 if (strlen(buffer) > 0) {
9657 strncpy(size, buffer, 99);
9659 if ((seperator = strchr(size, ','))
9660 || (seperator = strchr(size, ' '))
9661 || (seperator = strchr(size, '\0'))) {
9662 seperator[0] = '\0';
9665 mem_size = atoi(size);
9670 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9672 if (mem_size && param) {
9673 if (data->input_mem.buf)
9674 free(data->input_mem.buf);
9675 data->input_mem.buf = malloc(mem_size);
9677 if (data->input_mem.buf) {
9678 memcpy(data->input_mem.buf, param, mem_size);
9679 data->input_mem.len = mem_size;
9680 ret = MM_ERROR_NONE;
9682 LOGE("failed to alloc mem %d", mem_size);
9683 ret = MM_ERROR_PLAYER_INTERNAL;
9686 data->input_mem.offset = 0;
9687 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9694 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9696 gchar *location = NULL;
9699 int ret = MM_ERROR_NONE;
9701 if ((path = strstr(uri, "file://"))) {
9702 location = g_filename_from_uri(uri, NULL, &err);
9703 if (!location || (err != NULL)) {
9704 LOGE("Invalid URI '%s' for filesrc: %s", path,
9705 (err != NULL) ? err->message : "unknown error");
9709 MMPLAYER_FREEIF(location);
9711 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9712 return MM_ERROR_PLAYER_INVALID_URI;
9714 LOGD("path from uri: %s", location);
9717 path = (location != NULL) ? (location) : ((char *)uri);
9720 ret = _mmplayer_exist_file_path(path);
9722 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9723 if (ret == MM_ERROR_NONE) {
9724 if (_mmplayer_is_sdp_file(path)) {
9725 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9726 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9727 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9729 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9730 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9732 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9733 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9735 LOGE("invalid uri, could not play..");
9736 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9739 MMPLAYER_FREEIF(location);
9744 static mmplayer_video_decoded_data_info_t *
9745 __mmplayer_create_stream_from_pad(GstPad *pad)
9747 GstCaps *caps = NULL;
9748 GstStructure *structure = NULL;
9749 unsigned int fourcc = 0;
9750 const gchar *string_format = NULL;
9751 mmplayer_video_decoded_data_info_t *stream = NULL;
9753 MMPixelFormatType format;
9756 caps = gst_pad_get_current_caps(pad);
9758 LOGE("Caps is NULL.");
9763 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9765 structure = gst_caps_get_structure(caps, 0);
9766 gst_structure_get_int(structure, "width", &width);
9767 gst_structure_get_int(structure, "height", &height);
9768 string_format = gst_structure_get_string(structure, "format");
9771 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9772 format = _mmplayer_get_pixtype(fourcc);
9773 gst_video_info_from_caps(&info, caps);
9774 gst_caps_unref(caps);
9777 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9778 LOGE("Wrong condition!!");
9782 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9784 LOGE("failed to alloc mem for video data");
9788 stream->width = width;
9789 stream->height = height;
9790 stream->format = format;
9791 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9797 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9799 unsigned int pitch = 0;
9800 unsigned int size = 0;
9802 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9805 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9806 bo = gst_tizen_memory_get_bos(mem, index);
9808 stream->bo[index] = tbm_bo_ref(bo);
9810 LOGE("failed to get bo for index %d", index);
9813 for (index = 0; index < stream->plane_num; index++) {
9814 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9815 stream->stride[index] = pitch;
9817 stream->elevation[index] = size / pitch;
9819 stream->elevation[index] = stream->height;
9824 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9826 if (stream->format == MM_PIXEL_FORMAT_I420) {
9827 int ret = TBM_SURFACE_ERROR_NONE;
9828 tbm_surface_h surface;
9829 tbm_surface_info_s info;
9831 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9833 ret = tbm_surface_get_info(surface, &info);
9834 if (ret != TBM_SURFACE_ERROR_NONE) {
9835 tbm_surface_destroy(surface);
9839 tbm_surface_destroy(surface);
9840 stream->stride[0] = info.planes[0].stride;
9841 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9842 stream->stride[1] = info.planes[1].stride;
9843 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9844 stream->stride[2] = info.planes[2].stride;
9845 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9846 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9847 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9848 stream->stride[0] = stream->width * 4;
9849 stream->elevation[0] = stream->height;
9850 stream->bo_size = stream->stride[0] * stream->height;
9852 LOGE("Not support format %d", stream->format);
9860 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9862 tbm_bo_handle thandle;
9864 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9865 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9866 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9870 unsigned char *src = NULL;
9871 unsigned char *dest = NULL;
9872 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9874 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9876 LOGE("fail to gst_memory_map");
9880 if (!mapinfo.data) {
9881 LOGE("data pointer is wrong");
9885 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9886 if (!stream->bo[0]) {
9887 LOGE("Fail to tbm_bo_alloc!!");
9891 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9893 LOGE("thandle pointer is wrong");
9897 if (stream->format == MM_PIXEL_FORMAT_I420) {
9898 src_stride[0] = GST_ROUND_UP_4(stream->width);
9899 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9900 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9901 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9904 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9905 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9907 for (i = 0; i < 3; i++) {
9908 src = mapinfo.data + src_offset[i];
9909 dest = thandle.ptr + dest_offset[i];
9914 for (j = 0; j < stream->height >> k; j++) {
9915 memcpy(dest, src, stream->width>>k);
9916 src += src_stride[i];
9917 dest += stream->stride[i];
9920 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9921 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9923 LOGE("Not support format %d", stream->format);
9927 tbm_bo_unmap(stream->bo[0]);
9928 gst_memory_unmap(mem, &mapinfo);
9934 tbm_bo_unmap(stream->bo[0]);
9937 gst_memory_unmap(mem, &mapinfo);
9943 __mmplayer_set_pause_state(mmplayer_t *player)
9945 if (player->sent_bos)
9948 /* rtsp case, get content attrs by GstMessage */
9949 if (MMPLAYER_IS_RTSP_STREAMING(player))
9952 /* it's first time to update all content attrs. */
9953 _mmplayer_update_content_attrs(player, ATTR_ALL);
9957 __mmplayer_set_playing_state(mmplayer_t *player)
9959 gchar *audio_codec = NULL;
9961 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9962 /* initialize because auto resume is done well. */
9963 player->resumed_by_rewind = FALSE;
9964 player->playback_rate = 1.0;
9967 if (player->sent_bos)
9970 /* try to get content metadata */
9972 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9973 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9974 * legacy mmfw-player api
9976 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9978 if ((player->cmd == MMPLAYER_COMMAND_START)
9979 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9980 __mmplayer_handle_missed_plugin(player);
9983 /* check audio codec field is set or not
9984 * we can get it from typefinder or codec's caps.
9986 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9988 /* The codec format can't be sent for audio only case like amr, mid etc.
9989 * Because, parser don't make related TAG.
9990 * So, if it's not set yet, fill it with found data.
9993 if (g_strrstr(player->type_caps_str, "audio/midi"))
9994 audio_codec = "MIDI";
9995 else if (g_strrstr(player->type_caps_str, "audio/x-amr"))
9996 audio_codec = "AMR";
9997 else if (g_strrstr(player->type_caps_str, "audio/mpeg")
9998 && !g_strrstr(player->type_caps_str, "mpegversion=(int)1"))
9999 audio_codec = "AAC";
10001 audio_codec = "unknown";
10003 if (mm_player_set_attribute((MMHandleType)player, NULL,
10004 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
10005 LOGE("failed to set attribute");
10007 LOGD("set audio codec type with caps");