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 MMPLAYER_RECONFIGURE_LOCK(player);
1044 if (player->gapless.reconfigure && !player->msg_posted) {
1045 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1046 ret = GST_PAD_PROBE_DROP;
1048 MMPLAYER_RECONFIGURE_UNLOCK(player);
1051 case GST_EVENT_STREAM_START:
1053 __mmplayer_gst_selector_update_start_time(player, stream_type);
1056 case GST_EVENT_FLUSH_STOP:
1058 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1059 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1060 player->gapless.start_time[stream_type] = 0;
1063 case GST_EVENT_SEGMENT:
1068 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1069 gst_event_copy_segment(event, &segment);
1071 if (segment.format != GST_FORMAT_TIME)
1074 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1075 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1076 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1077 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1078 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1079 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1081 /* keep the all the segment ev to cover the seeking */
1082 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1083 player->gapless.update_segment[stream_type] = TRUE;
1085 if (!player->gapless.running)
1088 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1090 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1092 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1093 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1094 gst_event_unref(event);
1095 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1101 gdouble proportion = 0.0;
1102 GstClockTimeDiff diff = 0;
1103 GstClockTime timestamp = 0;
1104 gint64 running_time_diff = -1;
1105 GstQOSType type = 0;
1106 GstEvent *tmpev = NULL;
1108 running_time_diff = player->gapless.segment[stream_type].base;
1110 if (running_time_diff <= 0) /* don't need to adjust */
1113 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1114 gst_event_unref(event);
1116 if (timestamp < running_time_diff) {
1117 LOGW("QOS event from previous group");
1118 ret = GST_PAD_PROBE_DROP;
1123 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1124 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1125 stream_type, GST_TIME_ARGS(timestamp),
1126 GST_TIME_ARGS(running_time_diff),
1127 GST_TIME_ARGS(timestamp - running_time_diff));
1130 timestamp -= running_time_diff;
1132 /* That case is invalid for QoS events */
1133 if (diff < 0 && -diff > timestamp) {
1134 LOGW("QOS event from previous group");
1135 ret = GST_PAD_PROBE_DROP;
1139 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1140 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1150 gst_caps_unref(caps);
1154 /* create fakesink for audio or video path without audiobin or videobin */
1156 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1158 GstElement *pipeline = NULL;
1159 GstElement *fakesink = NULL;
1160 GstPad *sinkpad = NULL;
1163 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1165 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1168 fakesink = gst_element_factory_make("fakesink", NULL);
1169 if (fakesink == NULL) {
1170 LOGE("failed to create fakesink");
1174 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1175 LOGE("failed to add fakesink to pipeline");
1180 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1182 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1184 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1185 LOGE("failed to link fakesink");
1189 if (strstr(name, "video")) {
1190 if (player->v_stream_caps) {
1191 gst_caps_unref(player->v_stream_caps);
1192 player->v_stream_caps = NULL;
1194 if (player->ini.set_dump_element_flag)
1195 __mmplayer_add_dump_buffer_probe(player, fakesink);
1198 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1199 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1201 /* store it as it's sink element */
1202 __mmplayer_add_sink(player, fakesink, FALSE);
1205 gst_object_unref(GST_OBJECT(sinkpad));
1213 gst_object_unref(GST_OBJECT(sinkpad));
1216 gst_element_set_state(fakesink, GST_STATE_NULL);
1218 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1219 gst_object_unref(GST_OBJECT(fakesink));
1226 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1228 GstElement *pipeline = NULL;
1229 g_autoptr(GstElement) concat = NULL;
1230 g_autoptr(GstPad) srcpad = NULL;
1233 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1235 concat = gst_element_factory_make("concat", NULL);
1237 LOGE("failed to create concat");
1241 srcpad = gst_element_get_static_pad(concat, "src");
1243 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1244 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1245 __mmplayer_gst_combiner_blocked, NULL, NULL);
1246 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1247 __mmplayer_gst_combiner_event_probe, player, NULL);
1250 gst_element_set_state(concat, GST_STATE_PAUSED);
1252 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1253 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1254 LOGE("failed to add concat to pipeline");
1255 gst_element_set_state(concat, GST_STATE_NULL);
1259 LOGD("Create concat [%d] element", elem_idx);
1261 player->pipeline->mainbin[elem_idx].id = elem_idx;
1262 player->pipeline->mainbin[elem_idx].gst = concat;
1265 return g_steal_pointer(&concat);
1269 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1271 GstElement *pipeline = NULL;
1272 GstElement *selector = NULL;
1273 GstPad *srcpad = NULL;
1276 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1278 selector = gst_element_factory_make("input-selector", NULL);
1280 LOGE("failed to create input-selector");
1283 g_object_set(selector, "sync-streams", TRUE, NULL);
1285 srcpad = gst_element_get_static_pad(selector, "src");
1287 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1288 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1289 __mmplayer_gst_combiner_blocked, NULL, NULL);
1290 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1291 __mmplayer_gst_combiner_event_probe, player, NULL);
1293 gst_element_set_state(selector, GST_STATE_PAUSED);
1295 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1296 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1297 LOGE("failed to add selector to pipeline");
1299 if (player->track[stream_type].block_id != 0)
1300 gst_pad_remove_probe(srcpad, player->track[stream_type].block_id);
1301 player->track[stream_type].block_id = 0;
1303 if (player->track[stream_type].event_probe_id != 0)
1304 gst_pad_remove_probe(srcpad, player->track[stream_type].event_probe_id);
1305 player->track[stream_type].event_probe_id = 0;
1307 gst_object_unref(GST_OBJECT(srcpad));
1309 gst_element_set_state(selector, GST_STATE_NULL);
1310 gst_object_unref(GST_OBJECT(selector));
1314 gst_object_unref(GST_OBJECT(srcpad));
1316 player->pipeline->mainbin[elem_idx].id = elem_idx;
1317 player->pipeline->mainbin[elem_idx].gst = selector;
1324 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1326 mmplayer_t *player = (mmplayer_t *)data;
1327 GstElement *combiner = NULL;
1328 GstCaps *caps = NULL;
1329 GstStructure *str = NULL;
1330 const gchar *name = NULL;
1331 GstPad *sinkpad = NULL;
1332 gboolean first_track = FALSE;
1333 gboolean caps_ret = TRUE;
1335 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1336 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1339 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1340 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1342 LOGD("pad-added signal handling");
1344 /* get mimetype from caps */
1345 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1349 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1351 LOGD("detected mimetype : %s", name);
1354 if (strstr(name, "video")) {
1356 gchar *caps_str = NULL;
1358 caps_str = gst_caps_to_string(caps);
1359 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1360 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1361 player->set_mode.video_zc = true;
1363 MMPLAYER_FREEIF(caps_str);
1365 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1366 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1368 LOGD("surface type : %d", stype);
1370 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1371 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1375 /* in case of exporting video frame, it requires the 360 video filter.
1376 * it will be handled in _no_more_pads(). */
1377 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1378 __mmplayer_gst_make_fakesink(player, pad, name);
1382 if (MMPLAYER_USE_DECODEBIN(player)) {
1383 LOGD("video selector is required");
1384 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1386 LOGD("video concat is required");
1387 elem_idx = MMPLAYER_M_V_CONCAT;
1389 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1390 } else if (strstr(name, "audio")) {
1391 gint samplerate = 0;
1394 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1395 if (player->build_audio_offload)
1396 player->no_more_pad = TRUE; /* remove state holder */
1397 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1401 gst_structure_get_int(str, "rate", &samplerate);
1402 gst_structure_get_int(str, "channels", &channels);
1404 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1405 __mmplayer_gst_make_fakesink(player, pad, name);
1408 if (MMPLAYER_USE_DECODEBIN(player)) {
1409 LOGD("audio selector is required");
1410 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1412 LOGD("audio concat is required");
1413 elem_idx = MMPLAYER_M_A_CONCAT;
1415 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1417 } else if (strstr(name, "text")) {
1418 if (MMPLAYER_USE_DECODEBIN(player)) {
1419 LOGD("text selector is required");
1420 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1422 LOGD("text concat is required");
1423 elem_idx = MMPLAYER_M_T_CONCAT;
1425 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1427 LOGE("invalid caps info");
1431 /* check selector and create it */
1432 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1433 if (MMPLAYER_USE_DECODEBIN(player))
1434 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1436 combiner = __mmplayer_gst_make_concat(player, elem_idx, stream_type);
1442 LOGD("Combiner element is already created.");
1446 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1448 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1450 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1451 LOGE("failed to link combiner");
1452 gst_object_unref(GST_OBJECT(combiner));
1457 if (MMPLAYER_USE_DECODEBIN(player)) {
1458 LOGD("this track will be activated");
1459 g_object_set(combiner, "active-pad", sinkpad, NULL);
1463 if (MMPLAYER_USE_DECODEBIN(player)) {
1464 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1466 /* apply the text track information */
1467 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1468 mm_player_set_attribute((MMHandleType)player, NULL,
1469 "content_text_track_num", player->track[stream_type].total_track_num,
1470 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1471 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1478 gst_caps_unref(caps);
1481 gst_object_unref(GST_OBJECT(sinkpad));
1485 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1490 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1492 GstPad *srcpad = NULL;
1495 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1497 LOGD("type %d", type);
1500 LOGD("there is no %d track", type);
1504 srcpad = gst_element_get_static_pad(combiner, "src");
1506 LOGE("failed to get srcpad from combiner");
1510 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1512 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1514 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1515 if (player->track[type].block_id) {
1516 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1517 player->track[type].block_id = 0;
1521 gst_object_unref(GST_OBJECT(srcpad));
1530 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1532 gint active_index = 0;
1535 MMPLAYER_RETURN_IF_FAIL(player);
1537 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1539 /* change track to active pad */
1540 active_index = player->track[type].active_track_index;
1541 if ((active_index != DEFAULT_TRACK_INDEX) &&
1542 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1543 LOGW("failed to change %d type track to %d", type, active_index);
1544 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1548 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1549 mm_player_set_attribute((MMHandleType)player, NULL,
1550 "content_text_track_num", player->track[type].total_track_num,
1551 "current_text_track_index", player->track[type].active_track_index, NULL);
1558 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1561 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1563 if (!audio_selector) {
1564 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1566 /* in case the source is changed, output can be changed. */
1567 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1568 LOGD("remove previous audiobin if it exist");
1570 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1571 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1573 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1574 MMPLAYER_FREEIF(player->pipeline->audiobin);
1577 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1578 _mmplayer_pipeline_complete(NULL, player);
1583 /* apply the audio track information */
1584 if (MMPLAYER_USE_DECODEBIN(player))
1585 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1587 /* create audio sink path */
1588 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1589 LOGE("failed to create audio sink path");
1598 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1601 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1603 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1604 LOGD("text path is not supported");
1608 /* apply the text track information */
1609 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1611 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1612 player->has_closed_caption = TRUE;
1614 /* create text decode path */
1615 player->no_more_pad = TRUE;
1617 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1618 LOGE("failed to create text sink path");
1627 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1629 gint64 dur_bytes = 0L;
1632 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1633 player->pipeline->mainbin && player->streamer, FALSE);
1635 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1636 LOGE("fail to get duration.");
1638 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1639 * use file information was already set on Q2 when it was created. */
1640 _mm_player_streaming_set_queue2(player->streamer,
1641 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1642 TRUE, /* use_buffering */
1643 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1644 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1651 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1653 mmplayer_t *player = NULL;
1654 GstElement *video_selector = NULL;
1655 GstElement *audio_selector = NULL;
1656 GstElement *text_selector = NULL;
1659 player = (mmplayer_t *)data;
1661 LOGD("no-more-pad signal handling");
1663 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1664 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1665 LOGW("player is shutting down");
1669 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1670 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1671 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1672 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1673 LOGE("failed to set queue2 buffering");
1678 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1679 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1680 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1682 if (!video_selector && !audio_selector && !text_selector) {
1683 LOGW("there is no selector");
1684 player->no_more_pad = TRUE;
1688 /* create video path followed by video-select */
1689 if (video_selector && !audio_selector && !text_selector)
1690 player->no_more_pad = TRUE;
1692 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1695 /* create audio path followed by audio-select */
1696 if (audio_selector && !text_selector)
1697 player->no_more_pad = TRUE;
1699 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1702 /* create text path followed by text-select */
1703 __mmplayer_create_text_sink_path(player, text_selector);
1706 _mmplayer_set_reconfigure_state(player, FALSE);
1711 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1713 gboolean ret = FALSE;
1714 GstElement *pipeline = NULL;
1715 GstPad *sinkpad = NULL;
1718 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1719 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1721 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1723 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1725 LOGE("failed to get pad from sinkbin");
1731 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1732 LOGE("failed to link sinkbin for reusing");
1733 goto EXIT; /* exit either pass or fail */
1737 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1738 LOGE("failed to set state(READY) to sinkbin");
1743 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1744 LOGE("failed to add sinkbin to pipeline");
1749 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1750 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1755 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1756 LOGE("failed to set state(PAUSED) to sinkbin");
1765 gst_object_unref(GST_OBJECT(sinkpad));
1773 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1775 mmplayer_t *player = NULL;
1776 GstCaps *caps = NULL;
1777 gchar *caps_str = NULL;
1778 GstStructure *str = NULL;
1779 const gchar *name = NULL;
1780 GstElement *sinkbin = NULL;
1781 gboolean reusing = FALSE;
1782 gboolean caps_ret = TRUE;
1783 gchar *sink_pad_name = "sink";
1786 player = (mmplayer_t *)data;
1789 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1790 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1791 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1793 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1797 gst_caps_unref(caps);
1798 caps = gst_caps_ref(ref_caps);
1801 caps_str = gst_caps_to_string(caps);
1803 LOGD("detected mimetype : %s", name);
1805 if (strstr(name, "audio")) {
1806 if (player->pipeline->audiobin == NULL) {
1807 const gchar *audio_format = gst_structure_get_string(str, "format");
1809 LOGD("original audio format %s", audio_format);
1810 mm_player_set_attribute((MMHandleType)player, NULL,
1811 "content_audio_format", audio_format, strlen(audio_format), NULL);
1814 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1815 LOGE("failed to create audiobin. continuing without audio");
1819 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1820 LOGD("creating audiobin success");
1823 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1824 LOGD("reusing audiobin");
1825 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1827 } else if (strstr(name, "video")) {
1828 /* 1. zero copy is updated at _decode_pad_added()
1829 * 2. NULL surface type is handled in _decode_pad_added() */
1830 LOGD("zero copy %d", player->set_mode.video_zc);
1831 if (player->pipeline->videobin == NULL) {
1832 int surface_type = 0;
1833 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1834 LOGD("display_surface_type (%d)", surface_type);
1836 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1837 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1838 LOGE("failed to acquire video overlay resource");
1842 player->interrupted_by_resource = FALSE;
1844 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1845 LOGE("failed to create videobin. continuing without video");
1849 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1850 LOGD("creating videosink bin success");
1853 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1854 LOGD("re-using videobin");
1855 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1857 } else if (strstr(name, "text")) {
1858 if (player->pipeline->textbin == NULL) {
1859 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1860 LOGE("failed to create text sink bin. continuing without text");
1864 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1865 player->textsink_linked = 1;
1866 LOGD("creating textsink bin success");
1868 if (!player->textsink_linked) {
1869 LOGD("re-using textbin");
1871 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1872 player->textsink_linked = 1;
1874 /* linked textbin exist which means that the external subtitle path exist already */
1875 LOGW("ignoring internal subtitle since external subtitle is available");
1878 sink_pad_name = "text_sink";
1880 LOGW("unknown mime type %s, ignoring it", name);
1884 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1887 LOGD("[handle: %p] success to create and link sink bin", player);
1889 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1890 * streaming task. if the task blocked, then buffer will not flow to the next element
1891 *(autoplugging element). so this is special hack for streaming. please try to remove it
1893 /* dec stream count. we can remove fakesink if it's zero */
1894 if (player->num_dynamic_pad)
1895 player->num_dynamic_pad--;
1897 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1899 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1900 _mmplayer_pipeline_complete(NULL, player);
1904 MMPLAYER_FREEIF(caps_str);
1907 gst_caps_unref(caps);
1913 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1915 int required_angle = 0; /* Angle required for straight view */
1916 int rotation_angle = 0;
1918 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1919 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1921 /* Counter clockwise */
1922 switch (orientation) {
1927 required_angle = 270;
1930 required_angle = 180;
1933 required_angle = 90;
1937 rotation_angle = display_angle + required_angle;
1938 if (rotation_angle >= 360)
1939 rotation_angle -= 360;
1941 /* check if supported or not */
1942 if (rotation_angle % 90) {
1943 LOGD("not supported rotation angle = %d", rotation_angle);
1947 switch (rotation_angle) {
1949 *value = MM_DISPLAY_ROTATION_NONE;
1952 *value = MM_DISPLAY_ROTATION_90;
1955 *value = MM_DISPLAY_ROTATION_180;
1958 *value = MM_DISPLAY_ROTATION_270;
1962 LOGD("setting rotation property value : %d", *value);
1968 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1970 int display_rotation = 0;
1971 gchar *org_orient = NULL;
1972 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1975 LOGE("cannot get content attribute");
1976 return MM_ERROR_PLAYER_INTERNAL;
1979 if (display_angle) {
1980 /* update user rotation */
1981 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1983 /* Counter clockwise */
1984 switch (display_rotation) {
1985 case MM_DISPLAY_ROTATION_NONE:
1988 case MM_DISPLAY_ROTATION_90:
1989 *display_angle = 90;
1991 case MM_DISPLAY_ROTATION_180:
1992 *display_angle = 180;
1994 case MM_DISPLAY_ROTATION_270:
1995 *display_angle = 270;
1998 LOGW("wrong angle type : %d", display_rotation);
2001 LOGD("check user angle: %d", *display_angle);
2005 /* Counter clockwise */
2006 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2009 if (!strcmp(org_orient, "rotate-90"))
2011 else if (!strcmp(org_orient, "rotate-180"))
2013 else if (!strcmp(org_orient, "rotate-270"))
2016 LOGD("original rotation is %s", org_orient);
2018 LOGD("content_video_orientation get fail");
2021 LOGD("check orientation: %d", *orientation);
2024 return MM_ERROR_NONE;
2027 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2029 int rotation_value = 0;
2030 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2031 int display_angle = 0;
2034 /* check video sinkbin is created */
2035 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2038 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2040 /* get rotation value to set */
2041 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2042 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2043 LOGD("set video param : rotate %d", rotation_value);
2046 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2048 MMHandleType attrs = 0;
2052 /* check video sinkbin is created */
2053 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2054 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2057 attrs = MMPLAYER_GET_ATTRS(player);
2058 MMPLAYER_RETURN_IF_FAIL(attrs);
2060 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2061 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2062 LOGD("set video param : visible %d", visible);
2065 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2067 MMHandleType attrs = 0;
2068 int display_method = 0;
2071 /* check video sinkbin is created */
2072 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2075 attrs = MMPLAYER_GET_ATTRS(player);
2076 MMPLAYER_RETURN_IF_FAIL(attrs);
2078 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2079 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2080 LOGD("set video param : method %d", display_method);
2083 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2085 MMHandleType attrs = 0;
2089 /* check video sinkbin is created */
2090 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2093 attrs = MMPLAYER_GET_ATTRS(player);
2094 MMPLAYER_RETURN_IF_FAIL(attrs);
2096 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2097 MMPLAYER_RETURN_IF_FAIL(handle);
2099 gst_video_overlay_set_video_roi_area(
2100 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2101 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2102 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2103 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2106 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2108 MMHandleType attrs = 0;
2113 int win_roi_width = 0;
2114 int win_roi_height = 0;
2117 /* check video sinkbin is created */
2118 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2121 attrs = MMPLAYER_GET_ATTRS(player);
2122 MMPLAYER_RETURN_IF_FAIL(attrs);
2124 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2125 MMPLAYER_RETURN_IF_FAIL(handle);
2127 /* It should be set after setting window */
2128 mm_attrs_multiple_get(attrs, NULL,
2129 "display_win_roi_x", &win_roi_x,
2130 "display_win_roi_y", &win_roi_y,
2131 "display_win_roi_width", &win_roi_width,
2132 "display_win_roi_height", &win_roi_height, NULL);
2134 /* After setting window handle, set display roi area */
2135 gst_video_overlay_set_display_roi_area(
2136 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2137 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2138 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2139 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2142 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2144 MMHandleType attrs = 0;
2145 gchar *handle = NULL;
2147 /* check video sinkbin is created */
2148 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2151 attrs = MMPLAYER_GET_ATTRS(player);
2152 MMPLAYER_RETURN_IF_FAIL(attrs);
2154 /* common case if using overlay surface */
2155 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2156 MMPLAYER_RETURN_IF_FAIL(handle);
2158 gst_video_overlay_set_wl_window_exported_shell_handle(
2159 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2161 LOGD("set video param: exported_shell_handle (%s)", handle);
2164 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2166 MMHandleType attrs = 0;
2169 /* check video sinkbin is created */
2170 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2173 attrs = MMPLAYER_GET_ATTRS(player);
2174 MMPLAYER_RETURN_IF_FAIL(attrs);
2176 /* common case if using overlay surface */
2177 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2178 MMPLAYER_RETURN_IF_FAIL(handle);
2180 /* default is using wl_surface_id */
2181 LOGD("set video param : wl_surface_id %d", handle);
2182 gst_video_overlay_set_wl_window_wl_surface_id(
2183 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2188 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2190 gboolean update_all_param = FALSE;
2191 int curr_type = MM_DISPLAY_SURFACE_NUM;
2195 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2196 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2197 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2198 LOGW("videosink is not ready yet");
2199 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2202 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2204 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2205 LOGE("current type(%d) is wrong", curr_type);
2206 return MM_ERROR_PLAYER_INTERNAL;
2209 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2210 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2211 return MM_ERROR_PLAYER_INTERNAL;
2214 LOGD("param_name : %s", param_name);
2215 if (!g_strcmp0(param_name, "update_all_param"))
2216 update_all_param = TRUE;
2218 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2219 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2221 return MM_ERROR_NONE;
2223 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2224 __mmplayer_video_param_set_display_overlay(player);
2225 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2226 __mmplayer_video_param_set_display_method(player);
2227 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2228 __mmplayer_video_param_set_display_visible(player);
2229 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2230 __mmplayer_video_param_set_display_rotation(player);
2231 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2232 __mmplayer_video_param_set_roi_area(player);
2233 if (update_all_param)
2234 __mmplayer_video_param_set_video_roi_area(player);
2237 return MM_ERROR_NONE;
2240 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2242 gboolean disable_overlay = FALSE;
2245 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2246 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2247 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2249 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2250 LOGW("Display control is not supported");
2251 return MM_ERROR_PLAYER_INTERNAL;
2254 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2256 if (disable == (bool)disable_overlay) {
2257 LOGE("It's the same with current setting: (%d)", disable);
2258 return MM_ERROR_NONE;
2262 LOGE("disable overlay");
2263 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2265 /* release overlay resource */
2266 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2267 LOGE("failed to release overlay resource");
2268 return MM_ERROR_PLAYER_INTERNAL;
2271 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2272 LOGE("failed to acquire video overlay resource");
2273 return MM_ERROR_PLAYER_INTERNAL;
2275 player->interrupted_by_resource = FALSE;
2277 LOGD("enable overlay");
2278 __mmplayer_video_param_set_display_overlay(player);
2279 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2280 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2284 return MM_ERROR_NONE;
2288 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2290 int ret = MM_ERROR_NONE;
2291 mmplayer_t *player = (mmplayer_t *)hplayer;
2294 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2296 if (MMPLAYER_USE_DECODEBIN(player)) {
2297 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2302 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2303 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2304 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2306 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2308 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2310 /* release decoder resource */
2311 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2312 LOGE("failed to release video decoder resources");
2313 return MM_ERROR_PLAYER_INTERNAL;
2315 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2317 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2321 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2328 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2330 GList *bucket = element_bucket;
2331 mmplayer_gst_element_t *element = NULL;
2332 mmplayer_gst_element_t *prv_element = NULL;
2333 GstElement *tee_element = NULL;
2334 gint successful_link_count = 0;
2338 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2340 prv_element = (mmplayer_gst_element_t *)bucket->data;
2341 bucket = bucket->next;
2343 for (; bucket; bucket = bucket->next) {
2344 element = (mmplayer_gst_element_t *)bucket->data;
2346 if (element && element->gst) {
2347 if (prv_element && prv_element->gst) {
2348 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2350 prv_element->gst = tee_element;
2352 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2353 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2354 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2358 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2359 LOGD("linking [%s] to [%s] success",
2360 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2361 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2362 successful_link_count++;
2363 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2364 LOGD("keep audio-tee element for next audio pipeline branch");
2365 tee_element = prv_element->gst;
2368 LOGD("linking [%s] to [%s] failed",
2369 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2370 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2376 prv_element = element;
2381 return successful_link_count;
2385 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2387 GList *bucket = element_bucket;
2388 mmplayer_gst_element_t *element = NULL;
2389 int successful_add_count = 0;
2393 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2394 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2396 for (; bucket; bucket = bucket->next) {
2397 element = (mmplayer_gst_element_t *)bucket->data;
2399 if (element && element->gst) {
2400 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2401 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2402 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2403 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2406 successful_add_count++;
2412 return successful_add_count;
2416 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2418 mmplayer_t *player = (mmplayer_t *)data;
2419 GstCaps *caps = NULL;
2420 GstStructure *str = NULL;
2422 gboolean caps_ret = TRUE;
2426 MMPLAYER_RETURN_IF_FAIL(pad);
2427 MMPLAYER_RETURN_IF_FAIL(unused);
2428 MMPLAYER_RETURN_IF_FAIL(data);
2430 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2434 LOGD("name = %s", name);
2436 if (strstr(name, "audio")) {
2437 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2439 if (player->audio_stream_changed_cb) {
2440 LOGE("call the audio stream changed cb");
2441 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2443 } else if (strstr(name, "video")) {
2444 if ((name = gst_structure_get_string(str, "format")))
2445 player->set_mode.video_zc = name[0] == 'S';
2447 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2448 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2450 LOGW("invalid caps info");
2455 gst_caps_unref(caps);
2463 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2468 MMPLAYER_RETURN_IF_FAIL(player);
2470 if (player->audio_stream_buff_list) {
2471 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2472 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2475 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2476 __mmplayer_audio_stream_send_data(player, tmp);
2478 MMPLAYER_FREEIF(tmp->pcm_data);
2479 MMPLAYER_FREEIF(tmp);
2482 g_list_free(player->audio_stream_buff_list);
2483 player->audio_stream_buff_list = NULL;
2490 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2492 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2495 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2497 audio_stream.bitrate = a_buffer->bitrate;
2498 audio_stream.channel = a_buffer->channel;
2499 audio_stream.channel_mask = a_buffer->channel_mask;
2500 audio_stream.data_size = a_buffer->data_size;
2501 audio_stream.data = a_buffer->pcm_data;
2502 audio_stream.pcm_format = a_buffer->pcm_format;
2504 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2506 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2512 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2514 mmplayer_t *player = (mmplayer_t *)data;
2515 const gchar *pcm_format = NULL;
2518 guint64 channel_mask = 0;
2519 void *a_data = NULL;
2521 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2522 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2526 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2528 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2529 a_data = mapinfo.data;
2530 a_size = mapinfo.size;
2532 GstCaps *caps = gst_pad_get_current_caps(pad);
2533 GstStructure *structure = gst_caps_get_structure(caps, 0);
2535 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2537 pcm_format = gst_structure_get_string(structure, "format");
2538 gst_structure_get_int(structure, "rate", &rate);
2539 gst_structure_get_int(structure, "channels", &channel);
2540 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2541 gst_caps_unref(GST_CAPS(caps));
2543 /* In case of the sync is false, use buffer list. *
2544 * The num of buffer list depends on the num of audio channels */
2545 if (player->audio_stream_buff_list) {
2546 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2547 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2549 if (channel_mask == tmp->channel_mask) {
2551 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2553 if (tmp->data_size + a_size < tmp->buff_size) {
2554 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2555 tmp->data_size += a_size;
2557 /* send data to client */
2558 __mmplayer_audio_stream_send_data(player, tmp);
2560 if (a_size > tmp->buff_size) {
2561 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2562 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2563 if (tmp->pcm_data == NULL) {
2564 LOGE("failed to realloc data.");
2567 tmp->buff_size = a_size;
2569 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2570 memcpy(tmp->pcm_data, a_data, a_size);
2571 tmp->data_size = a_size;
2576 LOGE("data is empty in list.");
2582 /* create new audio stream data for newly found audio channel */
2583 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2584 if (a_buffer == NULL) {
2585 LOGE("failed to alloc data.");
2588 a_buffer->bitrate = rate;
2589 a_buffer->channel = channel;
2590 a_buffer->channel_mask = channel_mask;
2591 a_buffer->data_size = a_size;
2592 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2594 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2595 /* If sync is FALSE, use buffer list to reduce the IPC. */
2596 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2597 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2598 if (a_buffer->pcm_data == NULL) {
2599 LOGE("failed to alloc data.");
2600 MMPLAYER_FREEIF(a_buffer);
2603 memcpy(a_buffer->pcm_data, a_data, a_size);
2605 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2607 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2609 /* If sync is TRUE, send data directly. */
2610 a_buffer->pcm_data = a_data;
2611 __mmplayer_audio_stream_send_data(player, a_buffer);
2612 MMPLAYER_FREEIF(a_buffer);
2616 gst_buffer_unmap(buffer, &mapinfo);
2621 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2623 mmplayer_t *player = (mmplayer_t *)data;
2624 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2625 GstPad *sinkpad = NULL;
2626 GstElement *queue = NULL, *sink = NULL;
2629 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2631 queue = gst_element_factory_make("queue", NULL);
2632 if (queue == NULL) {
2633 LOGD("fail make queue");
2637 sink = gst_element_factory_make("fakesink", NULL);
2639 LOGD("fail make fakesink");
2643 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2645 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2646 LOGW("failed to link queue & sink");
2650 sinkpad = gst_element_get_static_pad(queue, "sink");
2652 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2653 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2657 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2659 gst_object_unref(sinkpad);
2660 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2661 g_object_set(sink, "sync", TRUE, NULL);
2662 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2664 /* keep the first sink reference only */
2665 if (!audiobin[MMPLAYER_A_SINK].gst) {
2666 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2667 audiobin[MMPLAYER_A_SINK].gst = sink;
2671 _mmplayer_add_signal_connection(player,
2673 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2675 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2678 __mmplayer_add_sink(player, sink, FALSE);
2680 if (!gst_element_sync_state_with_parent(queue)) {
2681 LOGE("failed to sync state");
2685 if (!gst_element_sync_state_with_parent(sink)) {
2686 LOGE("failed to sync state");
2694 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2696 gst_object_unref(GST_OBJECT(queue));
2700 gst_object_unref(GST_OBJECT(sink));
2704 gst_object_unref(GST_OBJECT(sinkpad));
2712 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2714 mmplayer_t *player = (mmplayer_t *)data;
2717 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2719 player->no_more_pad = TRUE;
2720 _mmplayer_pipeline_complete(NULL, player);
2727 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2729 #define MAX_PROPS_LEN 128
2730 mmplayer_gst_element_t *audiobin = NULL;
2731 gint latency_mode = 0;
2732 gchar *stream_type = NULL;
2733 gchar *latency = NULL;
2735 gchar stream_props[MAX_PROPS_LEN] = {0,};
2736 GstStructure *props = NULL;
2739 * It should be set after player creation through attribute.
2740 * But, it can not be changed during playing.
2743 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2745 audiobin = player->pipeline->audiobin;
2747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2748 if (player->sound.mute) {
2749 LOGD("mute enabled");
2750 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2753 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2754 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2757 snprintf(stream_props, sizeof(stream_props) - 1,
2758 "props,application.process.id.origin=%d", player->client_pid);
2760 snprintf(stream_props, sizeof(stream_props) - 1,
2761 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2762 stream_type, stream_id, player->client_pid);
2764 props = gst_structure_from_string(stream_props, NULL);
2765 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2766 LOGI("props result[%s].", stream_props);
2767 gst_structure_free(props);
2769 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2771 switch (latency_mode) {
2772 case AUDIO_LATENCY_MODE_LOW:
2773 latency = g_strdup("low");
2775 case AUDIO_LATENCY_MODE_MID:
2776 latency = g_strdup("mid");
2778 case AUDIO_LATENCY_MODE_HIGH:
2779 latency = g_strdup("high");
2782 latency = g_strdup("mid");
2786 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2788 LOGD("audiosink property - latency=%s", latency);
2790 MMPLAYER_FREEIF(latency);
2796 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2798 mmplayer_gst_element_t *audiobin = NULL;
2801 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2802 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2804 audiobin = player->pipeline->audiobin;
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2807 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2808 LOGE("failed to create media stream info");
2809 return MM_ERROR_PLAYER_INTERNAL;
2812 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2814 if (player->video360_yaw_radians <= M_PI &&
2815 player->video360_yaw_radians >= -M_PI &&
2816 player->video360_pitch_radians <= M_PI_2 &&
2817 player->video360_pitch_radians >= -M_PI_2) {
2818 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2819 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2820 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2821 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2822 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2823 "source-orientation-y", player->video360_metadata.init_view_heading,
2824 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2828 return MM_ERROR_NONE;
2832 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2834 mmplayer_gst_element_t *audiobin = NULL;
2835 GstPad *sink_pad = NULL;
2836 GstCaps *acaps = NULL;
2838 int pitch_control = 0;
2839 double pitch_value = 1.0;
2842 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2843 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2845 audiobin = player->pipeline->audiobin;
2847 LOGD("make element for normal audio playback");
2849 /* audio bin structure for playback. {} means optional.
2850 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2852 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2853 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2856 /* for pitch control */
2857 mm_attrs_multiple_get(player->attrs, NULL,
2858 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2859 MM_PLAYER_PITCH_VALUE, &pitch_value,
2862 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2863 if (pitch_control && (player->videodec_linked == 0)) {
2864 GstElementFactory *factory;
2866 factory = gst_element_factory_find("pitch");
2868 gst_object_unref(factory);
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2874 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2875 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2877 LOGW("there is no pitch element");
2882 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2884 /* replaygain volume */
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2886 if (player->sound.rg_enable)
2887 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2889 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2894 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2895 /* currently, only openalsink uses volume element */
2896 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2897 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2899 if (player->sound.mute) {
2900 LOGD("mute enabled");
2901 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2905 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2907 /* audio effect element. if audio effect is enabled */
2908 if ((strcmp(player->ini.audioeffect_element, ""))
2910 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2911 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2913 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2915 if ((!player->bypass_audio_effect)
2916 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2917 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2918 if (!_mmplayer_audio_effect_custom_apply(player))
2919 LOGI("apply audio effect(custom) setting success");
2923 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2924 && (player->set_mode.rich_audio)) {
2925 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2929 /* create audio sink */
2930 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2931 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2932 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2934 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2935 if (player->is_360_feature_enabled &&
2936 player->is_content_spherical &&
2938 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2939 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2940 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2942 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2946 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2947 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2948 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2949 gst_caps_unref(acaps);
2951 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2953 player->is_openal_plugin_used = TRUE;
2955 if (player->is_360_feature_enabled && player->is_content_spherical)
2956 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2957 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2960 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2961 (player->videodec_linked && player->ini.use_system_clock)) {
2962 LOGD("system clock will be used.");
2963 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2966 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2967 __mmplayer_gst_set_pulsesink_property(player);
2968 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2969 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2974 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2975 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2977 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2978 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2979 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2980 gst_object_unref(GST_OBJECT(sink_pad));
2982 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2985 return MM_ERROR_NONE;
2987 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2989 return MM_ERROR_PLAYER_INTERNAL;
2993 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2995 mmplayer_gst_element_t *audiobin = NULL;
2996 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2998 gchar *dst_format = NULL;
3000 int dst_samplerate = 0;
3001 int dst_channels = 0;
3002 GstCaps *caps = NULL;
3003 char *caps_str = NULL;
3006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3007 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3009 audiobin = player->pipeline->audiobin;
3011 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
3013 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
3015 [case 1] extract interleave audio pcm without playback
3016 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
3017 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
3019 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
3021 [case 2] deinterleave for each channel without playback
3022 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
3023 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
3025 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
3026 - fakesink (sync or not)
3029 [case 3] [case 1(sync only)] + playback
3030 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3032 * src - ... - tee - queue1 - playback path
3033 - queue2 - [case1 pipeline with sync]
3035 [case 4] [case 2(sync only)] + playback
3036 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3038 * src - ... - tee - queue1 - playback path
3039 - queue2 - [case2 pipeline with sync]
3043 /* 1. create tee and playback path
3044 'tee' should be added at first to copy the decoded stream
3046 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3047 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3048 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3050 /* tee - path 1 : for playback path */
3051 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3052 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3054 /* tee - path 2 : for extract path */
3055 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3056 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3059 /* if there is tee, 'tee - path 2' is linked here */
3061 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3064 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3066 /* 2. decide the extract pcm format */
3067 mm_attrs_multiple_get(player->attrs, NULL,
3068 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3069 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3070 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3073 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3074 dst_format, dst_len, dst_samplerate, dst_channels);
3076 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3077 mm_attrs_multiple_get(player->attrs, NULL,
3078 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3079 "content_audio_samplerate", &dst_samplerate,
3080 "content_audio_channels", &dst_channels,
3083 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3084 dst_format, dst_len, dst_samplerate, dst_channels);
3086 /* If there is no enough information, set it to platform default value. */
3087 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3088 LOGD("set platform default format");
3089 dst_format = DEFAULT_PCM_OUT_FORMAT;
3091 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3092 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3095 /* 3. create capsfilter */
3096 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3097 caps = gst_caps_new_simple("audio/x-raw",
3098 "format", G_TYPE_STRING, dst_format,
3099 "rate", G_TYPE_INT, dst_samplerate,
3100 "channels", G_TYPE_INT, dst_channels,
3103 caps_str = gst_caps_to_string(caps);
3104 LOGD("new caps : %s", caps_str);
3106 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3109 gst_caps_unref(caps);
3110 MMPLAYER_FREEIF(caps_str);
3112 /* 4-1. create deinterleave to extract pcm for each channel */
3113 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3114 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3115 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3117 /* audiosink will be added after getting signal for each channel */
3118 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3119 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3120 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3121 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3122 player->no_more_pad = FALSE;
3124 /* 4-2. create fakesink to extract interleaved pcm */
3125 LOGD("add audio fakesink for interleaved audio");
3126 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3127 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3128 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3129 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3131 _mmplayer_add_signal_connection(player,
3132 G_OBJECT(audiobin[extract_sink_id].gst),
3133 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3135 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3138 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3142 return MM_ERROR_NONE;
3144 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3146 return MM_ERROR_PLAYER_INTERNAL;
3150 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3152 int ret = MM_ERROR_NONE;
3153 mmplayer_gst_element_t *audiobin = NULL;
3154 GList *element_bucket = NULL;
3157 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3158 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3160 audiobin = player->pipeline->audiobin;
3162 if (player->build_audio_offload) { /* skip all the audio filters */
3163 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3165 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3166 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3167 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3169 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3173 /* FIXME: need to mention the supportable condition at API reference */
3174 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3175 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3177 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3179 if (ret != MM_ERROR_NONE)
3182 LOGD("success to make audio bin element");
3183 *bucket = element_bucket;
3186 return MM_ERROR_NONE;
3189 LOGE("failed to make audio bin element");
3190 g_list_free(element_bucket);
3194 return MM_ERROR_PLAYER_INTERNAL;
3198 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3200 mmplayer_gst_element_t *first_element = NULL;
3201 mmplayer_gst_element_t *audiobin = NULL;
3203 GstPad *ghostpad = NULL;
3204 GList *element_bucket = NULL;
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3211 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3213 LOGE("failed to allocate memory for audiobin");
3214 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3218 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3219 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3220 if (!audiobin[MMPLAYER_A_BIN].gst) {
3221 LOGE("failed to create audiobin");
3226 player->pipeline->audiobin = audiobin;
3228 /* create audio filters and audiosink */
3229 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3232 /* adding created elements to bin */
3233 LOGD("adding created elements to bin");
3234 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3237 /* linking elements in the bucket by added order. */
3238 LOGD("Linking elements in the bucket by added order.");
3239 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3242 /* get first element's sinkpad for creating ghostpad */
3243 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3244 if (!first_element) {
3245 LOGE("failed to get first elem");
3249 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3251 LOGE("failed to get pad from first element of audiobin");
3255 ghostpad = gst_ghost_pad_new("sink", pad);
3257 LOGE("failed to create ghostpad");
3261 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3262 LOGE("failed to add ghostpad to audiobin");
3266 gst_object_unref(pad);
3268 g_list_free(element_bucket);
3271 return MM_ERROR_NONE;
3274 LOGD("ERROR : releasing audiobin");
3277 gst_object_unref(GST_OBJECT(pad));
3280 gst_object_unref(GST_OBJECT(ghostpad));
3283 g_list_free(element_bucket);
3285 /* release element which are not added to bin */
3286 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3287 /* NOTE : skip bin */
3288 if (audiobin[i].gst) {
3289 GstObject *parent = NULL;
3290 parent = gst_element_get_parent(audiobin[i].gst);
3293 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3294 audiobin[i].gst = NULL;
3296 gst_object_unref(GST_OBJECT(parent));
3300 /* release audiobin with it's children */
3301 if (audiobin[MMPLAYER_A_BIN].gst)
3302 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3304 MMPLAYER_FREEIF(audiobin);
3306 player->pipeline->audiobin = NULL;
3308 return MM_ERROR_PLAYER_INTERNAL;
3312 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3314 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3318 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3320 int ret = MM_ERROR_NONE;
3322 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3323 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3325 MMPLAYER_VIDEO_BO_LOCK(player);
3327 if (player->video_bo_list) {
3328 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3329 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3330 if (tmp && tmp->bo == bo) {
3332 LOGD("release bo %p", bo);
3333 tbm_bo_unref(tmp->bo);
3334 MMPLAYER_VIDEO_BO_UNLOCK(player);
3335 MMPLAYER_VIDEO_BO_SIGNAL(player);
3340 /* hw codec is running or the list was reset for DRC. */
3341 LOGW("there is no bo list.");
3343 MMPLAYER_VIDEO_BO_UNLOCK(player);
3345 LOGW("failed to find bo %p", bo);
3349 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3355 tbm_bo_unref(tmp->bo);
3360 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3363 MMPLAYER_RETURN_IF_FAIL(player);
3365 MMPLAYER_VIDEO_BO_LOCK(player);
3366 if (player->video_bo_list) {
3367 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3368 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3369 player->video_bo_list = NULL;
3371 player->video_bo_size = 0;
3372 MMPLAYER_VIDEO_BO_UNLOCK(player);
3379 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3382 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3383 gboolean ret = TRUE;
3384 gint64 end_time = 0;
3386 /* check DRC, if it is, destroy the prev bo list to create again */
3387 if (player->video_bo_size != size) {
3388 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3389 __mmplayer_video_stream_destroy_bo_list(player);
3390 player->video_bo_size = size;
3393 MMPLAYER_VIDEO_BO_LOCK(player);
3395 if ((!player->video_bo_list) ||
3396 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3398 /* create bo list */
3400 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3402 if (player->video_bo_list) {
3403 /* if bo list did not created all, try it again. */
3404 idx = g_list_length(player->video_bo_list);
3405 LOGD("bo list exist(len: %d)", idx);
3408 for (; idx < player->ini.num_of_video_bo; idx++) {
3409 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3411 LOGE("Fail to alloc bo_info.");
3414 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3416 LOGE("Fail to tbm_bo_alloc.");
3417 MMPLAYER_FREEIF(bo_info);
3420 bo_info->used = FALSE;
3421 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3424 /* update video num buffers */
3425 LOGD("video_num_buffers : %d", idx);
3426 mm_player_set_attribute((MMHandleType)player, NULL,
3427 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3428 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3432 MMPLAYER_VIDEO_BO_UNLOCK(player);
3437 if (player->ini.video_bo_timeout > 0)
3438 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3441 /* get bo from list*/
3442 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3443 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3444 if (tmp && (tmp->used == FALSE)) {
3445 LOGD("found bo %p to use", tmp->bo);
3447 MMPLAYER_VIDEO_BO_UNLOCK(player);
3448 return tbm_bo_ref(tmp->bo);
3452 if (player->ini.video_bo_timeout <= 0) {
3453 MMPLAYER_VIDEO_BO_WAIT(player);
3455 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3457 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3463 MMPLAYER_VIDEO_BO_UNLOCK(player);
3468 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3470 mmplayer_t *player = (mmplayer_t *)data;
3472 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3474 /* send prerolled pkt */
3475 player->video_stream_prerolled = false;
3477 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3479 /* not to send prerolled pkt again */
3480 player->video_stream_prerolled = true;
3484 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3486 mmplayer_t *player = (mmplayer_t *)data;
3487 mmplayer_video_decoded_data_info_t *stream = NULL;
3488 GstMemory *mem = NULL;
3491 MMPLAYER_RETURN_IF_FAIL(player);
3492 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3494 if (player->video_stream_prerolled) {
3495 player->video_stream_prerolled = false;
3496 LOGD("skip the prerolled pkt not to send it again");
3500 /* clear stream data structure */
3501 stream = __mmplayer_create_stream_from_pad(pad);
3503 LOGE("failed to alloc stream");
3507 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3509 /* set size and timestamp */
3510 mem = gst_buffer_peek_memory(buffer, 0);
3511 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3512 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3514 /* check zero-copy */
3515 if (player->set_mode.video_zc &&
3516 player->set_mode.video_export &&
3517 gst_is_tizen_memory(mem)) {
3518 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3519 stream->internal_buffer = gst_buffer_ref(buffer);
3520 } else { /* sw codec */
3521 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3524 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3528 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3529 LOGE("failed to send video decoded data.");
3536 LOGE("release video stream resource.");
3537 if (gst_is_tizen_memory(mem)) {
3539 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3541 tbm_bo_unref(stream->bo[i]);
3544 /* unref gst buffer */
3545 if (stream->internal_buffer)
3546 gst_buffer_unref(stream->internal_buffer);
3549 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3551 MMPLAYER_FREEIF(stream);
3556 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3558 mmplayer_gst_element_t *videobin = NULL;
3561 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3563 videobin = player->pipeline->videobin;
3565 /* Set spatial media metadata and/or user settings to the element.
3567 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3568 "projection-type", player->video360_metadata.projection_type, NULL);
3570 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3571 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3573 if (player->video360_metadata.full_pano_width_pixels &&
3574 player->video360_metadata.full_pano_height_pixels &&
3575 player->video360_metadata.cropped_area_image_width &&
3576 player->video360_metadata.cropped_area_image_height) {
3577 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3578 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3579 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3580 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3581 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3582 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3583 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3587 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3588 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3589 "horizontal-fov", player->video360_horizontal_fov,
3590 "vertical-fov", player->video360_vertical_fov, NULL);
3593 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3594 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3595 "zoom", 1.0f / player->video360_zoom, NULL);
3598 if (player->video360_yaw_radians <= M_PI &&
3599 player->video360_yaw_radians >= -M_PI &&
3600 player->video360_pitch_radians <= M_PI_2 &&
3601 player->video360_pitch_radians >= -M_PI_2) {
3602 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3603 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3604 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3605 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3606 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3607 "pose-yaw", player->video360_metadata.init_view_heading,
3608 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3611 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3612 "passthrough", !player->is_video360_enabled, NULL);
3619 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3621 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3622 GList *element_bucket = NULL;
3625 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3627 /* create video360 filter */
3628 if (player->is_360_feature_enabled && player->is_content_spherical) {
3629 LOGD("create video360 element");
3630 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3631 __mmplayer_gst_set_video360_property(player);
3635 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3636 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3637 player->set_mode.video_zc) {
3638 LOGD("skip creating the videoconv and rotator");
3639 return MM_ERROR_NONE;
3642 /* in case of sw codec & overlay surface type, except 360 playback.
3643 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3644 LOGD("create video converter: %s", video_csc);
3645 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3648 *bucket = element_bucket;
3650 return MM_ERROR_NONE;
3652 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3653 g_list_free(element_bucket);
3657 return MM_ERROR_PLAYER_INTERNAL;
3661 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3663 gchar *factory_name = NULL;
3665 switch (surface_type) {
3666 case MM_DISPLAY_SURFACE_OVERLAY:
3668 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3669 if (strlen(player->ini.videosink_element_overlay) > 0)
3670 factory_name = player->ini.videosink_element_overlay;
3672 case MM_DISPLAY_SURFACE_REMOTE:
3674 case MM_DISPLAY_SURFACE_NULL:
3675 if (strlen(player->ini.videosink_element_fake) > 0)
3676 factory_name = player->ini.videosink_element_fake;
3679 LOGE("unidentified surface type");
3683 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3684 return factory_name;
3688 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3690 gchar *factory_name = NULL;
3691 mmplayer_gst_element_t *videobin = NULL;
3696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3698 videobin = player->pipeline->videobin;
3699 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3701 attrs = MMPLAYER_GET_ATTRS(player);
3703 LOGE("cannot get content attribute");
3704 return MM_ERROR_PLAYER_INTERNAL;
3707 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3708 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3709 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3710 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3711 "use-tbm", use_tbm, NULL);
3714 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3715 return MM_ERROR_PLAYER_INTERNAL;
3717 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3720 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3721 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3724 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3726 LOGD("disable last-sample");
3727 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3730 if (player->set_mode.video_export) {
3732 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3733 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3734 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3736 _mmplayer_add_signal_connection(player,
3737 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3738 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3740 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3743 _mmplayer_add_signal_connection(player,
3744 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3745 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3747 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3751 if (videobin[MMPLAYER_V_SINK].gst) {
3752 GstPad *sink_pad = NULL;
3753 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3755 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3756 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3757 gst_object_unref(GST_OBJECT(sink_pad));
3759 LOGE("failed to get sink pad from videosink");
3763 return MM_ERROR_NONE;
3768 * - video overlay surface(arm/x86) : tizenwlsink
3771 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3774 GList *element_bucket = NULL;
3775 mmplayer_gst_element_t *first_element = NULL;
3776 mmplayer_gst_element_t *videobin = NULL;
3777 gchar *videosink_factory_name = NULL;
3780 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3783 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3785 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3787 player->pipeline->videobin = videobin;
3790 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3791 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3792 if (!videobin[MMPLAYER_V_BIN].gst) {
3793 LOGE("failed to create videobin");
3797 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3800 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3801 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3803 /* additional setting for sink plug-in */
3804 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3805 LOGE("failed to set video property");
3809 /* store it as it's sink element */
3810 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3812 /* adding created elements to bin */
3813 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3814 LOGE("failed to add elements");
3818 /* Linking elements in the bucket by added order */
3819 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3820 LOGE("failed to link elements");
3824 /* get first element's sinkpad for creating ghostpad */
3825 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3826 if (!first_element) {
3827 LOGE("failed to get first element from bucket");
3831 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3833 LOGE("failed to get pad from first element");
3837 /* create ghostpad */
3838 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3839 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3840 LOGE("failed to add ghostpad to videobin");
3843 gst_object_unref(pad);
3845 /* done. free allocated variables */
3846 g_list_free(element_bucket);
3850 return MM_ERROR_NONE;
3853 LOGE("ERROR : releasing videobin");
3854 g_list_free(element_bucket);
3857 gst_object_unref(GST_OBJECT(pad));
3859 /* release videobin with it's children */
3860 if (videobin[MMPLAYER_V_BIN].gst)
3861 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3863 MMPLAYER_FREEIF(videobin);
3864 player->pipeline->videobin = NULL;
3866 return MM_ERROR_PLAYER_INTERNAL;
3870 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3872 GList *element_bucket = NULL;
3873 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3875 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3876 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3877 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3878 "signal-handoffs", FALSE,
3881 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3882 _mmplayer_add_signal_connection(player,
3883 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3884 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3886 G_CALLBACK(__mmplayer_update_subtitle),
3889 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3890 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3892 if (!player->play_subtitle) {
3893 LOGD("add textbin sink as sink element of whole pipeline.");
3894 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3897 /* adding created elements to bin */
3898 LOGD("adding created elements to bin");
3899 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3900 LOGE("failed to add elements");
3904 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3905 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3906 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3908 /* linking elements in the bucket by added order. */
3909 LOGD("Linking elements in the bucket by added order.");
3910 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3911 LOGE("failed to link elements");
3915 if (textbin[MMPLAYER_T_QUEUE].gst) {
3917 GstPad *ghostpad = NULL;
3919 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3921 LOGE("failed to get sink pad of text queue");
3925 ghostpad = gst_ghost_pad_new("text_sink", pad);
3926 gst_object_unref(pad);
3929 LOGE("failed to create ghostpad of textbin");
3933 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3934 LOGE("failed to add ghostpad to textbin");
3935 gst_object_unref(ghostpad);
3940 g_list_free(element_bucket);
3942 return MM_ERROR_NONE;
3946 g_list_free(element_bucket);
3948 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3949 LOGE("remove textbin sink from sink list");
3950 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3953 /* release element at __mmplayer_gst_create_text_sink_bin */
3954 return MM_ERROR_PLAYER_INTERNAL;
3958 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3960 mmplayer_gst_element_t *textbin = NULL;
3961 int surface_type = 0;
3966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3969 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3971 LOGE("failed to allocate memory for textbin");
3972 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3976 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3977 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3978 if (!textbin[MMPLAYER_T_BIN].gst) {
3979 LOGE("failed to create textbin");
3984 player->pipeline->textbin = textbin;
3987 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3988 LOGD("surface type for subtitle : %d", surface_type);
3989 switch (surface_type) {
3990 case MM_DISPLAY_SURFACE_OVERLAY:
3991 case MM_DISPLAY_SURFACE_NULL:
3992 case MM_DISPLAY_SURFACE_REMOTE:
3993 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3994 LOGE("failed to make plain text elements");
4005 return MM_ERROR_NONE;
4009 LOGD("ERROR : releasing textbin");
4011 /* release signal */
4012 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4014 /* release element which are not added to bin */
4015 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4016 /* NOTE : skip bin */
4017 if (textbin[i].gst) {
4018 GstObject *parent = NULL;
4019 parent = gst_element_get_parent(textbin[i].gst);
4022 gst_object_unref(GST_OBJECT(textbin[i].gst));
4023 textbin[i].gst = NULL;
4025 gst_object_unref(GST_OBJECT(parent));
4030 /* release textbin with it's children */
4031 if (textbin[MMPLAYER_T_BIN].gst)
4032 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4034 MMPLAYER_FREEIF(textbin);
4035 player->pipeline->textbin = NULL;
4038 return MM_ERROR_PLAYER_INTERNAL;
4042 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4044 mmplayer_gst_element_t *mainbin = NULL;
4045 mmplayer_gst_element_t *textbin = NULL;
4046 MMHandleType attrs = 0;
4047 GstElement *subsrc = NULL;
4048 GstElement *subparse = NULL;
4049 gchar *subtitle_uri = NULL;
4050 const gchar *charset = NULL;
4056 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4058 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4060 mainbin = player->pipeline->mainbin;
4062 attrs = MMPLAYER_GET_ATTRS(player);
4064 LOGE("cannot get content attribute");
4065 return MM_ERROR_PLAYER_INTERNAL;
4068 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4069 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4070 LOGE("subtitle uri is not proper filepath.");
4071 return MM_ERROR_PLAYER_INVALID_URI;
4074 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4075 LOGE("failed to get storage info of subtitle path");
4076 return MM_ERROR_PLAYER_INVALID_URI;
4079 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4081 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4082 player->subtitle_language_list = NULL;
4083 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4085 /* create the subtitle source */
4086 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4088 LOGE("failed to create filesrc element");
4091 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4093 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4094 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4096 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4097 LOGW("failed to add queue");
4098 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4099 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4100 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4105 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4107 LOGE("failed to create subparse element");
4111 charset = _mmplayer_get_charset(subtitle_uri);
4113 LOGD("detected charset is %s", charset);
4114 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4117 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4118 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4120 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4121 LOGW("failed to add subparse");
4122 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4123 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4124 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4128 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4129 LOGW("failed to link subsrc and subparse");
4133 player->play_subtitle = TRUE;
4134 player->adjust_subtitle_pos = 0;
4136 LOGD("play subtitle using subtitle file");
4138 if (player->pipeline->textbin == NULL) {
4139 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4140 LOGE("failed to create text sink bin. continuing without text");
4144 textbin = player->pipeline->textbin;
4146 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4147 LOGW("failed to add textbin");
4149 /* release signal */
4150 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4152 /* release textbin with it's children */
4153 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4154 MMPLAYER_FREEIF(player->pipeline->textbin);
4155 player->pipeline->textbin = textbin = NULL;
4159 LOGD("link text input selector and textbin ghost pad");
4161 player->textsink_linked = 1;
4162 player->external_text_idx = 0;
4163 LOGI("textsink is linked");
4165 textbin = player->pipeline->textbin;
4166 LOGD("text bin has been created. reuse it.");
4167 player->external_text_idx = 1;
4170 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4171 LOGW("failed to link subparse and textbin");
4175 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4177 LOGE("failed to get sink pad from textsink to probe data");
4181 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4182 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4184 gst_object_unref(pad);
4187 /* create dot. for debugging */
4188 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4191 return MM_ERROR_NONE;
4194 /* release text pipeline resource */
4195 player->textsink_linked = 0;
4197 /* release signal */
4198 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4200 if (player->pipeline->textbin) {
4201 LOGE("remove textbin");
4203 /* release textbin with it's children */
4204 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4205 MMPLAYER_FREEIF(player->pipeline->textbin);
4206 player->pipeline->textbin = NULL;
4210 /* release subtitle elem */
4211 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4212 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4214 return MM_ERROR_PLAYER_INTERNAL;
4218 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4220 mmplayer_t *player = (mmplayer_t *)data;
4221 MMMessageParamType msg = {0, };
4222 GstClockTime duration = 0;
4223 gpointer text = NULL;
4224 guint text_size = 0;
4225 gboolean ret = TRUE;
4226 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4230 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4231 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4233 if (player->is_subtitle_force_drop) {
4234 LOGW("subtitle is dropped forcedly.");
4238 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4239 text = mapinfo.data;
4240 text_size = mapinfo.size;
4242 if (player->set_mode.subtitle_off) {
4243 LOGD("subtitle is OFF.");
4247 if (!text || (text_size == 0)) {
4248 LOGD("There is no subtitle to be displayed.");
4252 msg.data = (void *)text;
4254 duration = GST_BUFFER_DURATION(buffer);
4256 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4257 if (player->duration > GST_BUFFER_PTS(buffer))
4258 duration = player->duration - GST_BUFFER_PTS(buffer);
4261 LOGI("subtitle duration is invalid, subtitle duration change "
4262 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4264 msg.subtitle.duration = (unsigned long)GST_TIME_AS_MSECONDS(duration);
4266 LOGD("update subtitle : [%lu msec] %s", msg.subtitle.duration, (char *)msg.data);
4268 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4269 gst_buffer_unmap(buffer, &mapinfo);
4276 static GstPadProbeReturn
4277 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4279 mmplayer_t *player = (mmplayer_t *)u_data;
4280 GstClockTime cur_timestamp = 0;
4281 gint64 adjusted_timestamp = 0;
4282 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4284 MMPLAYER_RETURN_VAL_IF_FAIL(player, GST_PAD_PROBE_DROP);
4286 if (player->set_mode.subtitle_off)
4287 return GST_PAD_PROBE_OK;
4289 if (player->adjust_subtitle_pos == 0)
4290 return GST_PAD_PROBE_OK;
4292 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4293 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4295 if (adjusted_timestamp < 0) {
4296 LOGD("adjusted_timestamp under zero");
4298 return GST_PAD_PROBE_DROP;
4301 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4302 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4303 GST_TIME_ARGS(cur_timestamp),
4304 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4306 return GST_PAD_PROBE_OK;
4310 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4314 /* check player and subtitlebin are created */
4315 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4316 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4318 if (position == 0) {
4319 LOGD("nothing to do");
4321 return MM_ERROR_NONE;
4324 /* check current position */
4325 player->adjust_subtitle_pos = position;
4327 LOGD("save adjust_subtitle_pos in player");
4331 return MM_ERROR_NONE;
4335 * This function is to create audio or video pipeline for playing.
4337 * @param player [in] handle of player
4339 * @return This function returns zero on success.
4344 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4346 int ret = MM_ERROR_NONE;
4347 mmplayer_gst_element_t *mainbin = NULL;
4348 MMHandleType attrs = 0;
4351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4353 /* get profile attribute */
4354 attrs = MMPLAYER_GET_ATTRS(player);
4356 LOGE("failed to get content attribute");
4360 /* create pipeline handles */
4361 if (player->pipeline) {
4362 LOGE("pipeline should be released before create new one");
4366 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4368 /* create mainbin */
4369 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4370 if (mainbin == NULL)
4373 /* create pipeline */
4374 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4375 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4376 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4377 LOGE("failed to create pipeline");
4382 player->pipeline->mainbin = mainbin;
4384 /* create the source and decoder elements */
4385 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4386 ret = _mmplayer_gst_build_es_pipeline(player);
4388 if (MMPLAYER_USE_DECODEBIN(player))
4389 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4391 ret = _mmplayer_gst_build_pipeline_with_src(player);
4394 if (ret != MM_ERROR_NONE) {
4395 LOGE("failed to create some elements");
4399 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4400 if (__mmplayer_check_subtitle(player)
4401 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4402 LOGE("failed to create text pipeline");
4405 ret = _mmplayer_gst_add_bus_watch(player);
4406 if (ret != MM_ERROR_NONE) {
4407 LOGE("failed to add bus watch");
4412 return MM_ERROR_NONE;
4415 _mmplayer_bus_watcher_remove(player);
4416 __mmplayer_gst_destroy_pipeline(player);
4417 return MM_ERROR_PLAYER_INTERNAL;
4421 __mmplayer_reset_gapless_state(mmplayer_t *player)
4424 MMPLAYER_RETURN_IF_FAIL(player
4426 && player->pipeline->audiobin
4427 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4429 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4436 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4439 int ret = MM_ERROR_NONE;
4443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4445 /* cleanup stuffs */
4446 MMPLAYER_FREEIF(player->type_caps_str);
4447 player->no_more_pad = FALSE;
4448 player->num_dynamic_pad = 0;
4450 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4451 player->subtitle_language_list = NULL;
4452 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4454 MMPLAYER_RECONFIGURE_LOCK(player);
4455 __mmplayer_reset_gapless_state(player);
4456 MMPLAYER_RECONFIGURE_UNLOCK(player);
4458 if (player->streamer) {
4459 _mm_player_streaming_initialize(player->streamer, FALSE);
4460 _mm_player_streaming_destroy(player->streamer);
4461 player->streamer = NULL;
4464 /* cleanup unlinked mime type */
4465 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4466 MMPLAYER_FREEIF(player->unlinked_video_mime);
4467 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4469 /* cleanup running stuffs */
4470 _mmplayer_cancel_eos_timer(player);
4472 /* cleanup gst stuffs */
4473 if (player->pipeline) {
4474 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4475 GstTagList *tag_list = player->pipeline->tag_list;
4477 /* first we need to disconnect all signal hander */
4478 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4481 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4482 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4483 gst_object_unref(bus);
4485 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4486 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4487 if (ret != MM_ERROR_NONE) {
4488 LOGE("fail to change state to NULL");
4489 return MM_ERROR_PLAYER_INTERNAL;
4492 LOGW("succeeded in changing state to NULL");
4494 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4497 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4498 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4500 MMPLAYER_FREEIF(player->pipeline->audiobin);
4501 MMPLAYER_FREEIF(player->pipeline->videobin);
4502 MMPLAYER_FREEIF(player->pipeline->textbin);
4503 MMPLAYER_FREEIF(mainbin);
4507 gst_tag_list_unref(tag_list);
4509 MMPLAYER_FREEIF(player->pipeline);
4511 MMPLAYER_FREEIF(player->album_art);
4513 if (player->v_stream_caps) {
4514 gst_caps_unref(player->v_stream_caps);
4515 player->v_stream_caps = NULL;
4518 if (player->a_stream_caps) {
4519 gst_caps_unref(player->a_stream_caps);
4520 player->a_stream_caps = NULL;
4523 if (player->s_stream_caps) {
4524 gst_caps_unref(player->s_stream_caps);
4525 player->s_stream_caps = NULL;
4527 _mmplayer_track_destroy(player);
4529 if (player->sink_elements)
4530 g_list_free(player->sink_elements);
4531 player->sink_elements = NULL;
4533 if (player->bufmgr) {
4534 tbm_bufmgr_deinit(player->bufmgr);
4535 player->bufmgr = NULL;
4538 LOGW("finished destroy pipeline");
4546 __mmplayer_gst_realize(mmplayer_t *player)
4549 int ret = MM_ERROR_NONE;
4553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4555 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4557 ret = __mmplayer_gst_create_pipeline(player);
4559 LOGE("failed to create pipeline");
4563 /* set pipeline state to READY */
4564 /* NOTE : state change to READY must be performed sync. */
4565 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4566 ret = _mmplayer_gst_set_state(player,
4567 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4569 if (ret != MM_ERROR_NONE) {
4570 /* return error if failed to set state */
4571 LOGE("failed to set READY state");
4575 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4577 /* create dot before error-return. for debugging */
4578 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4586 __mmplayer_gst_unrealize(mmplayer_t *player)
4588 int ret = MM_ERROR_NONE;
4592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4594 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4595 MMPLAYER_PRINT_STATE(player);
4597 /* release miscellaneous information */
4598 __mmplayer_release_misc(player);
4600 /* destroy pipeline */
4601 ret = __mmplayer_gst_destroy_pipeline(player);
4602 if (ret != MM_ERROR_NONE) {
4603 LOGE("failed to destroy pipeline");
4607 /* release miscellaneous information.
4608 these info needs to be released after pipeline is destroyed. */
4609 __mmplayer_release_misc_post(player);
4611 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4619 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4624 LOGW("set_message_callback is called with invalid player handle");
4625 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4628 player->msg_cb = callback;
4629 player->msg_cb_param = user_param;
4631 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4635 return MM_ERROR_NONE;
4639 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4641 int ret = MM_ERROR_NONE;
4646 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4647 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4648 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4650 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4652 if (strstr(uri, "es_buff://")) {
4653 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4654 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4655 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4656 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4658 tmp = g_ascii_strdown(uri, strlen(uri));
4659 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4660 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4662 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4664 } else if (strstr(uri, "mms://")) {
4665 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4666 } else if ((path = strstr(uri, "mem://"))) {
4667 ret = __mmplayer_set_mem_uri(data, path, param);
4669 ret = __mmplayer_set_file_uri(data, uri);
4672 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4673 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4674 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4675 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4677 /* dump parse result */
4678 SECURE_LOGW("incoming uri : %s", uri);
4679 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4680 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4688 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4691 mmplayer_t *player = NULL;
4692 MMMessageParamType msg = {0, };
4694 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4699 LOGE("user_data is null");
4703 player = (mmplayer_t *)user_data;
4705 if (!player->pipeline || !player->attrs) {
4706 LOGW("not initialized");
4710 LOGD("cmd lock player, cmd state : %d", player->cmd);
4711 MMPLAYER_CMD_LOCK(player);
4712 LOGD("cmd locked player");
4714 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4715 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4716 LOGW("player already destroyed");
4717 MMPLAYER_CMD_UNLOCK(player);
4721 player->interrupted_by_resource = TRUE;
4723 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4725 /* get last play position */
4726 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4727 msg.union_type = MM_MSG_UNION_TIME;
4728 msg.time.elapsed = pos;
4729 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4731 LOGW("failed to get play position.");
4734 LOGD("video resource conflict so, resource will be freed by unrealizing");
4735 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4736 LOGE("failed to unrealize");
4738 MMPLAYER_CMD_UNLOCK(player);
4740 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4741 player->hw_resource[res_idx] = NULL;
4745 return TRUE; /* release all the resources */
4749 __mmplayer_initialize_video_roi(mmplayer_t *player)
4751 player->video_roi.scale_x = 0.0;
4752 player->video_roi.scale_y = 0.0;
4753 player->video_roi.scale_width = 1.0;
4754 player->video_roi.scale_height = 1.0;
4758 _mmplayer_create_player(MMHandleType handle)
4760 int ret = MM_ERROR_PLAYER_INTERNAL;
4761 bool enabled = false;
4763 mmplayer_t *player = MM_PLAYER_CAST(handle);
4767 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4769 /* initialize player state */
4770 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4771 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4772 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4773 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4775 /* check current state */
4776 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4778 /* construct attributes */
4779 player->attrs = _mmplayer_construct_attribute(handle);
4781 if (!player->attrs) {
4782 LOGE("Failed to construct attributes");
4786 /* initialize gstreamer with configured parameter */
4787 if (!__mmplayer_init_gstreamer(player)) {
4788 LOGE("Initializing gstreamer failed");
4789 _mmplayer_deconstruct_attribute(handle);
4793 /* create lock. note that g_tread_init() has already called in gst_init() */
4794 g_mutex_init(&player->fsink_lock);
4796 /* create update tag lock */
4797 g_mutex_init(&player->update_tag_lock);
4799 /* create gapless play mutex */
4800 g_mutex_init(&player->gapless_play_thread_mutex);
4802 /* create gapless play cond */
4803 g_cond_init(&player->gapless_play_thread_cond);
4805 /* create gapless play thread */
4806 player->gapless_play_thread =
4807 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4808 if (!player->gapless_play_thread) {
4809 LOGE("failed to create gapless play thread");
4810 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4811 g_mutex_clear(&player->gapless_play_thread_mutex);
4812 g_cond_clear(&player->gapless_play_thread_cond);
4816 player->bus_msg_q = g_queue_new();
4817 if (!player->bus_msg_q) {
4818 LOGE("failed to create queue for bus_msg");
4819 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4823 ret = _mmplayer_initialize_video_capture(player);
4824 if (ret != MM_ERROR_NONE) {
4825 LOGW("video capture is not supported");
4826 /* do not handle as error for headless profile */
4829 /* initialize resource manager */
4830 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4831 __resource_release_cb, player, &player->resource_manager)
4832 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4833 LOGE("failed to create resource manager");
4834 ret = MM_ERROR_PLAYER_INTERNAL;
4838 /* create video bo lock and cond */
4839 g_mutex_init(&player->video_bo_mutex);
4840 g_cond_init(&player->video_bo_cond);
4842 /* create subtitle info lock and cond */
4843 g_mutex_init(&player->subtitle_info_mutex);
4844 g_cond_init(&player->subtitle_info_cond);
4846 player->streaming_type = STREAMING_SERVICE_NONE;
4848 /* give default value of audio effect setting */
4849 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4850 player->sound.rg_enable = false;
4851 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4853 player->play_subtitle = FALSE;
4854 player->has_closed_caption = FALSE;
4855 player->pending_resume = FALSE;
4856 if (player->ini.dump_element_keyword[0][0] == '\0')
4857 player->ini.set_dump_element_flag = FALSE;
4859 player->ini.set_dump_element_flag = TRUE;
4861 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4862 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4863 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4865 /* Set video360 settings to their defaults for just-created player.
4868 player->is_360_feature_enabled = FALSE;
4869 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4870 LOGI("spherical feature info: %d", enabled);
4872 player->is_360_feature_enabled = TRUE;
4874 LOGE("failed to get spherical feature info");
4877 player->is_content_spherical = FALSE;
4878 player->is_video360_enabled = TRUE;
4879 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4880 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4881 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4882 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4883 player->video360_zoom = 1.0f;
4884 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4885 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4887 __mmplayer_initialize_video_roi(player);
4889 /* set player state to null */
4890 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4891 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4895 return MM_ERROR_NONE;
4899 g_mutex_clear(&player->fsink_lock);
4900 /* free update tag lock */
4901 g_mutex_clear(&player->update_tag_lock);
4902 g_queue_free(player->bus_msg_q);
4903 player->bus_msg_q = NULL;
4904 /* free gapless play thread */
4905 if (player->gapless_play_thread) {
4906 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4907 player->gapless_play_thread_exit = TRUE;
4908 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4909 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4911 g_thread_join(player->gapless_play_thread);
4912 player->gapless_play_thread = NULL;
4914 g_mutex_clear(&player->gapless_play_thread_mutex);
4915 g_cond_clear(&player->gapless_play_thread_cond);
4918 /* release attributes */
4919 _mmplayer_deconstruct_attribute(handle);
4927 __mmplayer_init_gstreamer(mmplayer_t *player)
4929 static gboolean initialized = FALSE;
4930 static const int max_argc = 50;
4932 gchar **argv = NULL;
4933 gchar **argv2 = NULL;
4939 LOGD("gstreamer already initialized.");
4944 argc = malloc(sizeof(int));
4945 argv = malloc(sizeof(gchar *) * max_argc);
4946 argv2 = malloc(sizeof(gchar *) * max_argc);
4948 if (!argc || !argv || !argv2)
4951 memset(argv, 0, sizeof(gchar *) * max_argc);
4952 memset(argv2, 0, sizeof(gchar *) * max_argc);
4956 argv[0] = g_strdup("mmplayer");
4959 for (i = 0; i < 5; i++) {
4960 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4961 if (strlen(player->ini.gst_param[i]) > 0) {
4962 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4967 /* we would not do fork for scanning plugins */
4968 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4971 /* check disable registry scan */
4972 if (player->ini.skip_rescan) {
4973 argv[*argc] = g_strdup("--gst-disable-registry-update");
4977 /* check disable segtrap */
4978 if (player->ini.disable_segtrap) {
4979 argv[*argc] = g_strdup("--gst-disable-segtrap");
4983 LOGD("initializing gstreamer with following parameter");
4984 LOGD("argc : %d", *argc);
4987 for (i = 0; i < arg_count; i++) {
4989 LOGD("argv[%d] : %s", i, argv2[i]);
4992 /* initializing gstreamer */
4993 if (!gst_init_check(argc, &argv, &err)) {
4994 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
5001 for (i = 0; i < arg_count; i++) {
5003 LOGD("release - argv[%d] : %s", i, argv2[i]);
5005 MMPLAYER_FREEIF(argv2[i]);
5008 MMPLAYER_FREEIF(argv);
5009 MMPLAYER_FREEIF(argv2);
5010 MMPLAYER_FREEIF(argc);
5020 for (i = 0; i < arg_count; i++) {
5021 LOGD("free[%d] : %s", i, argv2[i]);
5022 MMPLAYER_FREEIF(argv2[i]);
5025 MMPLAYER_FREEIF(argv);
5026 MMPLAYER_FREEIF(argv2);
5027 MMPLAYER_FREEIF(argc);
5033 __mmplayer_check_async_state_transition(mmplayer_t *player)
5035 GstState element_state = GST_STATE_VOID_PENDING;
5036 GstState element_pending_state = GST_STATE_VOID_PENDING;
5037 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5038 GstElement *element = NULL;
5039 gboolean async = FALSE;
5041 /* check player handle */
5042 MMPLAYER_RETURN_IF_FAIL(player &&
5044 player->pipeline->mainbin &&
5045 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5048 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5050 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5051 LOGD("don't need to check the pipeline state");
5055 MMPLAYER_PRINT_STATE(player);
5057 /* wait for state transition */
5058 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5059 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5061 if (ret == GST_STATE_CHANGE_FAILURE) {
5062 LOGE(" [%s] state : %s pending : %s",
5063 GST_ELEMENT_NAME(element),
5064 gst_element_state_get_name(element_state),
5065 gst_element_state_get_name(element_pending_state));
5067 /* dump state of all element */
5068 _mmplayer_dump_pipeline_state(player);
5073 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5078 _mmplayer_destroy(MMHandleType handle)
5080 mmplayer_t *player = MM_PLAYER_CAST(handle);
5084 /* check player handle */
5085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5087 /* destroy can called at anytime */
5088 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5090 /* check async state transition */
5091 __mmplayer_check_async_state_transition(player);
5093 /* release gapless play thread */
5094 if (player->gapless_play_thread) {
5095 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5096 player->gapless_play_thread_exit = TRUE;
5097 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5098 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5100 LOGD("waiting for gapless play thread exit");
5101 g_thread_join(player->gapless_play_thread);
5102 g_mutex_clear(&player->gapless_play_thread_mutex);
5103 g_cond_clear(&player->gapless_play_thread_cond);
5104 LOGD("gapless play thread released");
5107 _mmplayer_release_video_capture(player);
5109 /* release miscellaneous information */
5110 __mmplayer_release_misc(player);
5112 /* release pipeline */
5113 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5114 LOGE("failed to destroy pipeline");
5115 return MM_ERROR_PLAYER_INTERNAL;
5118 __mmplayer_destroy_hw_resource(player);
5120 g_queue_free(player->bus_msg_q);
5122 /* release subtitle info lock and cond */
5123 g_mutex_clear(&player->subtitle_info_mutex);
5124 g_cond_clear(&player->subtitle_info_cond);
5126 __mmplayer_release_dump_list(player->dump_list);
5128 /* release miscellaneous information.
5129 these info needs to be released after pipeline is destroyed. */
5130 __mmplayer_release_misc_post(player);
5132 /* release attributes */
5133 _mmplayer_deconstruct_attribute(handle);
5135 if (player->uri_info.uri_list) {
5136 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5137 player->uri_info.uri_list = NULL;
5141 g_mutex_clear(&player->fsink_lock);
5144 g_mutex_clear(&player->update_tag_lock);
5146 /* release video bo lock and cond */
5147 g_mutex_clear(&player->video_bo_mutex);
5148 g_cond_clear(&player->video_bo_cond);
5152 return MM_ERROR_NONE;
5156 _mmplayer_realize(MMHandleType hplayer)
5158 mmplayer_t *player = (mmplayer_t *)hplayer;
5159 int ret = MM_ERROR_NONE;
5162 MMHandleType attrs = 0;
5166 /* check player handle */
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 /* check current state */
5170 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5172 attrs = MMPLAYER_GET_ATTRS(player);
5174 LOGE("fail to get attributes.");
5175 return MM_ERROR_PLAYER_INTERNAL;
5177 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5178 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5180 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5181 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5183 if (ret != MM_ERROR_NONE) {
5184 LOGE("failed to parse profile");
5189 if (uri && (strstr(uri, "es_buff://"))) {
5190 if (strstr(uri, "es_buff://push_mode"))
5191 player->es_player_push_mode = TRUE;
5193 player->es_player_push_mode = FALSE;
5196 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5197 LOGW("mms protocol is not supported format.");
5198 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5201 if (MMPLAYER_IS_STREAMING(player))
5202 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5204 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5206 player->smooth_streaming = FALSE;
5207 player->videodec_linked = 0;
5208 player->audiodec_linked = 0;
5209 player->textsink_linked = 0;
5210 player->is_external_subtitle_present = FALSE;
5211 player->is_external_subtitle_added_now = FALSE;
5212 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5213 player->video360_metadata.is_spherical = -1;
5214 player->is_openal_plugin_used = FALSE;
5215 player->subtitle_language_list = NULL;
5216 player->is_subtitle_force_drop = FALSE;
5218 _mmplayer_track_initialize(player);
5219 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5221 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5222 gint prebuffer_ms = 0, rebuffer_ms = 0;
5224 player->streamer = _mm_player_streaming_create();
5225 _mm_player_streaming_initialize(player->streamer, TRUE);
5227 mm_attrs_multiple_get(player->attrs, NULL,
5228 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5229 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5231 if (prebuffer_ms > 0) {
5232 prebuffer_ms = MAX(prebuffer_ms, 1000);
5233 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5236 if (rebuffer_ms > 0) {
5237 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5238 rebuffer_ms = MAX(rebuffer_ms, 1000);
5239 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5242 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5243 player->streamer->buffering_req.rebuffer_time);
5246 /* realize pipeline */
5247 ret = __mmplayer_gst_realize(player);
5248 if (ret != MM_ERROR_NONE)
5249 LOGE("fail to realize the player.");
5251 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5259 _mmplayer_unrealize(MMHandleType hplayer)
5261 mmplayer_t *player = (mmplayer_t *)hplayer;
5262 int ret = MM_ERROR_NONE;
5263 int rm_ret = MM_ERROR_NONE;
5264 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 MMPLAYER_CMD_UNLOCK(player);
5271 _mmplayer_bus_watcher_remove(player);
5272 /* destroy the gst bus msg thread which is created during realize.
5273 this funct have to be called before getting cmd lock. */
5274 _mmplayer_bus_msg_thread_destroy(player);
5275 MMPLAYER_CMD_LOCK(player);
5277 /* check current state */
5278 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5280 /* check async state transition */
5281 __mmplayer_check_async_state_transition(player);
5283 /* unrealize pipeline */
5284 ret = __mmplayer_gst_unrealize(player);
5286 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5287 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5288 if (rm_ret != MM_ERROR_NONE)
5289 LOGE("failed to release [%d] resources", res_idx);
5292 player->interrupted_by_resource = FALSE;
5299 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5301 mmplayer_t *player = (mmplayer_t *)hplayer;
5303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5305 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5309 _mmplayer_get_state(MMHandleType hplayer, int *state)
5311 mmplayer_t *player = (mmplayer_t *)hplayer;
5313 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5315 *state = MMPLAYER_CURRENT_STATE(player);
5317 return MM_ERROR_NONE;
5321 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5323 GstElement *vol_element = NULL;
5324 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5328 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5330 /* check pipeline handle */
5331 if (!player->pipeline || !player->pipeline->audiobin) {
5332 LOGD("'%s' will be applied when audiobin is created", prop_name);
5334 /* NOTE : stored value will be used in create_audiobin
5335 * returning MM_ERROR_NONE here makes application to able to
5336 * set audio volume or mute at anytime.
5338 return MM_ERROR_NONE;
5341 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5342 volume_elem_id = MMPLAYER_A_SINK;
5344 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5346 LOGE("failed to get vol element %d", volume_elem_id);
5347 return MM_ERROR_PLAYER_INTERNAL;
5350 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5352 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5353 LOGE("there is no '%s' property", prop_name);
5354 return MM_ERROR_PLAYER_INTERNAL;
5357 if (!strcmp(prop_name, "volume")) {
5358 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5359 } else if (!strcmp(prop_name, "mute")) {
5360 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5362 LOGE("invalid property %s", prop_name);
5363 return MM_ERROR_PLAYER_INTERNAL;
5366 return MM_ERROR_NONE;
5370 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5372 int ret = MM_ERROR_NONE;
5373 mmplayer_t *player = (mmplayer_t *)hplayer;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 LOGD("volume = %f", volume);
5380 /* invalid factor range or not */
5381 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5382 LOGE("Invalid volume value");
5383 return MM_ERROR_INVALID_ARGUMENT;
5386 player->sound.volume = volume;
5388 ret = __mmplayer_gst_set_volume_property(player, "volume");
5395 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5397 mmplayer_t *player = (mmplayer_t *)hplayer;
5401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5402 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5404 *volume = player->sound.volume;
5406 LOGD("current vol = %f", *volume);
5409 return MM_ERROR_NONE;
5413 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5415 int ret = MM_ERROR_NONE;
5416 mmplayer_t *player = (mmplayer_t *)hplayer;
5419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421 LOGD("mute = %d", mute);
5423 player->sound.mute = mute;
5425 ret = __mmplayer_gst_set_volume_property(player, "mute");
5432 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5434 mmplayer_t *player = (mmplayer_t *)hplayer;
5438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5439 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5441 *mute = player->sound.mute;
5443 LOGD("current mute = %d", *mute);
5447 return MM_ERROR_NONE;
5451 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5453 mmplayer_t *player = (mmplayer_t *)hplayer;
5457 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459 player->audio_stream_changed_cb = callback;
5460 player->audio_stream_changed_cb_user_param = user_param;
5461 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5465 return MM_ERROR_NONE;
5469 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5471 mmplayer_t *player = (mmplayer_t *)hplayer;
5475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5477 player->audio_decoded_cb = callback;
5478 player->audio_decoded_cb_user_param = user_param;
5479 player->audio_extract_opt = opt;
5480 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5484 return MM_ERROR_NONE;
5488 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5490 mmplayer_t *player = (mmplayer_t *)hplayer;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 if (callback && !player->bufmgr)
5497 player->bufmgr = tbm_bufmgr_init(-1);
5499 player->set_mode.video_export = (callback) ? true : false;
5500 player->video_decoded_cb = callback;
5501 player->video_decoded_cb_user_param = user_param;
5503 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5507 return MM_ERROR_NONE;
5511 _mmplayer_start(MMHandleType hplayer)
5513 mmplayer_t *player = (mmplayer_t *)hplayer;
5514 gint ret = MM_ERROR_NONE;
5518 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5520 /* check current state */
5521 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5523 /* start pipeline */
5524 ret = _mmplayer_gst_start(player);
5525 if (ret != MM_ERROR_NONE)
5526 LOGE("failed to start player.");
5528 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5529 LOGD("force playing start even during buffering");
5530 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5538 /* NOTE: post "not supported codec message" to application
5539 * when one codec is not found during AUTOPLUGGING in MSL.
5540 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5541 * And, if any codec is not found, don't send message here.
5542 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5545 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5547 MMMessageParamType msg_param;
5548 memset(&msg_param, 0, sizeof(MMMessageParamType));
5549 gboolean post_msg_direct = FALSE;
5553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5555 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5556 player->not_supported_codec, player->can_support_codec);
5558 if (player->not_found_demuxer) {
5559 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5560 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5562 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5563 MMPLAYER_FREEIF(msg_param.data);
5565 return MM_ERROR_NONE;
5568 if (player->not_supported_codec) {
5569 if (player->can_support_codec) {
5570 // There is one codec to play
5571 post_msg_direct = TRUE;
5573 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5574 post_msg_direct = TRUE;
5577 if (post_msg_direct) {
5578 MMMessageParamType msg_param;
5579 memset(&msg_param, 0, sizeof(MMMessageParamType));
5581 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5582 LOGW("not found AUDIO codec, posting error code to application.");
5584 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5585 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5586 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5587 LOGW("not found VIDEO codec, posting error code to application.");
5589 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5590 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5593 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5595 MMPLAYER_FREEIF(msg_param.data);
5597 return MM_ERROR_NONE;
5599 // no any supported codec case
5600 LOGW("not found any codec, posting error code to application.");
5602 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5603 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5604 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5606 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5607 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5610 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5612 MMPLAYER_FREEIF(msg_param.data);
5618 return MM_ERROR_NONE;
5621 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5623 GstState element_state = GST_STATE_VOID_PENDING;
5624 GstState element_pending_state = GST_STATE_VOID_PENDING;
5625 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5626 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5628 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5630 MMPLAYER_RECONFIGURE_LOCK(player);
5631 if (!player->gapless.reconfigure) {
5632 MMPLAYER_RECONFIGURE_UNLOCK(player);
5636 LOGI("reconfigure is under process");
5637 MMPLAYER_RECONFIGURE_WAIT(player);
5638 MMPLAYER_RECONFIGURE_UNLOCK(player);
5639 LOGI("reconfigure is completed.");
5641 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5642 &element_state, &element_pending_state, timeout * GST_SECOND);
5643 if (result == GST_STATE_CHANGE_FAILURE)
5644 LOGW("failed to get pipeline state in %d sec", timeout);
5649 /* NOTE : it should be able to call 'stop' anytime*/
5651 _mmplayer_stop(MMHandleType hplayer)
5653 mmplayer_t *player = (mmplayer_t *)hplayer;
5654 int ret = MM_ERROR_NONE;
5658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5660 /* check current state */
5661 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5663 /* need to wait till the rebuilding pipeline is completed */
5664 __mmplayer_check_pipeline_reconfigure_state(player);
5665 MMPLAYER_RECONFIGURE_LOCK(player);
5666 __mmplayer_reset_gapless_state(player);
5667 MMPLAYER_RECONFIGURE_UNLOCK(player);
5669 /* NOTE : application should not wait for EOS after calling STOP */
5670 _mmplayer_cancel_eos_timer(player);
5673 player->seek_state = MMPLAYER_SEEK_NONE;
5676 ret = _mmplayer_gst_stop(player);
5678 if (ret != MM_ERROR_NONE)
5679 LOGE("failed to stop player.");
5687 _mmplayer_pause(MMHandleType hplayer)
5689 mmplayer_t *player = (mmplayer_t *)hplayer;
5690 gint64 pos_nsec = 0;
5691 gboolean async = FALSE;
5692 gint ret = MM_ERROR_NONE;
5696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5698 /* check current state */
5699 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5701 /* check pipeline reconfigure state */
5702 __mmplayer_check_pipeline_reconfigure_state(player);
5704 switch (MMPLAYER_CURRENT_STATE(player)) {
5705 case MM_PLAYER_STATE_READY:
5707 /* check prepare async or not.
5708 * In the case of streaming playback, it's recommended to avoid blocking wait.
5710 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5711 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5713 /* Changing back sync of rtspsrc to async */
5714 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5715 LOGD("async prepare working mode for rtsp");
5721 case MM_PLAYER_STATE_PLAYING:
5723 /* NOTE : store current point to overcome some bad operation
5724 *(returning zero when getting current position in paused state) of some
5727 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5728 LOGW("getting current position failed in paused");
5730 player->last_position = pos_nsec;
5732 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5733 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5734 This causes problem is position calculation during normal pause resume scenarios also.
5735 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5736 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5737 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5738 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5744 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5745 LOGD("doing async pause in case of ms buff src");
5749 /* pause pipeline */
5750 ret = _mmplayer_gst_pause(player, async);
5751 if (ret != MM_ERROR_NONE) {
5752 LOGE("failed to pause player. ret : 0x%x", ret);
5753 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5757 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5758 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5759 LOGE("failed to update display_rotation");
5763 return MM_ERROR_NONE;
5766 /* in case of streaming, pause could take long time.*/
5768 _mmplayer_abort_pause(MMHandleType hplayer)
5770 mmplayer_t *player = (mmplayer_t *)hplayer;
5771 int ret = MM_ERROR_NONE;
5775 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5777 player->pipeline->mainbin,
5778 MM_ERROR_PLAYER_NOT_INITIALIZED);
5780 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5781 LOGD("set the videobin state to READY");
5782 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5783 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5787 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5788 LOGD("set the audiobin state to READY");
5789 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5790 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5794 LOGD("set the pipeline state to READY");
5795 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5796 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5798 if (ret != MM_ERROR_NONE) {
5799 LOGE("fail to change state to READY");
5800 return MM_ERROR_PLAYER_INTERNAL;
5803 LOGD("succeeded in changing state to READY");
5808 _mmplayer_resume(MMHandleType hplayer)
5810 mmplayer_t *player = (mmplayer_t *)hplayer;
5811 int ret = MM_ERROR_NONE;
5812 gboolean async = FALSE;
5816 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5818 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5819 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5820 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5824 /* Changing back sync mode rtspsrc to async */
5825 LOGD("async resume for rtsp case");
5829 /* check current state */
5830 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5832 ret = _mmplayer_gst_resume(player, async);
5833 if (ret != MM_ERROR_NONE)
5834 LOGE("failed to resume player.");
5836 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5837 LOGD("force resume even during buffering");
5838 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5847 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5849 mmplayer_t *player = (mmplayer_t *)hplayer;
5850 gint64 pos_nsec = 0;
5851 int ret = MM_ERROR_NONE;
5853 signed long long start = 0, stop = 0;
5854 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5857 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5858 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5860 /* The sound of video is not supported under 0.0 and over 2.0. */
5861 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5862 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5865 _mmplayer_set_mute(hplayer, mute);
5867 if (player->playback_rate == rate)
5868 return MM_ERROR_NONE;
5870 /* If the position is reached at start potion during fast backward, EOS is posted.
5871 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5873 player->playback_rate = rate;
5875 current_state = MMPLAYER_CURRENT_STATE(player);
5877 if (current_state != MM_PLAYER_STATE_PAUSED)
5878 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5880 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5882 if ((current_state == MM_PLAYER_STATE_PAUSED)
5883 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5884 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5885 pos_nsec = player->last_position;
5890 stop = GST_CLOCK_TIME_NONE;
5892 start = GST_CLOCK_TIME_NONE;
5896 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5897 player->playback_rate,
5899 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5900 GST_SEEK_TYPE_SET, start,
5901 GST_SEEK_TYPE_SET, stop)) {
5902 LOGE("failed to set speed playback");
5903 return MM_ERROR_PLAYER_SEEK;
5906 LOGD("succeeded to set speed playback as %0.1f", rate);
5910 return MM_ERROR_NONE;;
5914 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5916 mmplayer_t *player = (mmplayer_t *)hplayer;
5917 int ret = MM_ERROR_NONE;
5921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5923 /* check pipeline reconfigure state */
5924 __mmplayer_check_pipeline_reconfigure_state(player);
5926 ret = _mmplayer_gst_set_position(player, position, FALSE);
5934 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5936 mmplayer_t *player = (mmplayer_t *)hplayer;
5937 int ret = MM_ERROR_NONE;
5939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5940 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5942 if (g_strrstr(player->type_caps_str, "video/mpegts"))
5943 __mmplayer_update_duration_value(player);
5945 *duration = player->duration;
5950 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5952 mmplayer_t *player = (mmplayer_t *)hplayer;
5953 int ret = MM_ERROR_NONE;
5955 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5957 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5963 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5965 mmplayer_t *player = (mmplayer_t *)hplayer;
5966 int ret = MM_ERROR_NONE;
5970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5972 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5980 __mmplayer_is_midi_type(gchar *str_caps)
5982 if ((g_strrstr(str_caps, "audio/midi")) ||
5983 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5984 (g_strrstr(str_caps, "application/x-smaf")) ||
5985 (g_strrstr(str_caps, "audio/x-imelody")) ||
5986 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5987 (g_strrstr(str_caps, "audio/xmf")) ||
5988 (g_strrstr(str_caps, "audio/mxmf"))) {
5997 __mmplayer_is_only_mp3_type(gchar *str_caps)
5999 if (g_strrstr(str_caps, "application/x-id3") ||
6000 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
6006 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
6008 GstStructure *caps_structure = NULL;
6009 gint samplerate = 0;
6013 MMPLAYER_RETURN_IF_FAIL(player && caps);
6015 caps_structure = gst_caps_get_structure(caps, 0);
6017 /* set stream information */
6018 gst_structure_get_int(caps_structure, "rate", &samplerate);
6019 gst_structure_get_int(caps_structure, "channels", &channels);
6021 mm_player_set_attribute((MMHandleType)player, NULL,
6022 "content_audio_samplerate", samplerate,
6023 "content_audio_channels", channels, NULL);
6025 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6029 __mmplayer_update_content_type_info(mmplayer_t *player)
6032 MMPLAYER_RETURN_IF_FAIL(player && player->type_caps_str);
6034 if (__mmplayer_is_midi_type(player->type_caps_str)) {
6035 player->bypass_audio_effect = TRUE;
6039 if (!player->streamer) {
6040 LOGD("no need to check streaming type");
6044 if (g_strrstr(player->type_caps_str, "application/x-hls")) {
6045 /* If it can't know exact type when it parses uri because of redirection case,
6046 * it will be fixed by typefinder or when doing autoplugging.
6048 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6049 player->streamer->is_adaptive_streaming = TRUE;
6050 } else if (g_strrstr(player->type_caps_str, "application/dash+xml")) {
6051 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6052 player->streamer->is_adaptive_streaming = TRUE;
6055 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6056 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type_caps_str, "video/mpegts"))) {
6057 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6059 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6060 if (player->streamer->is_adaptive_streaming)
6061 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6063 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6067 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6072 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6073 GstCaps *caps, gpointer data)
6075 mmplayer_t *player = (mmplayer_t *)data;
6079 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6081 MMPLAYER_FREEIF(player->type_caps_str);
6082 player->type_caps_str = gst_caps_to_string(caps);
6083 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6084 player, player->type_caps_str, probability, gst_caps_get_size(caps));
6086 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6087 (g_strrstr(player->type_caps_str, "audio/x-raw-int"))) {
6088 LOGE("not support media format");
6090 if (player->msg_posted == FALSE) {
6091 MMMessageParamType msg_param;
6092 memset(&msg_param, 0, sizeof(MMMessageParamType));
6094 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6095 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6097 /* don't post more if one was sent already */
6098 player->msg_posted = TRUE;
6103 __mmplayer_update_content_type_info(player);
6105 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6108 pad = gst_element_get_static_pad(tf, "src");
6110 LOGE("fail to get typefind src pad.");
6114 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6115 gboolean async = FALSE;
6116 LOGE("failed to autoplug %s", player->type_caps_str);
6118 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6120 if (async && player->msg_posted == FALSE)
6121 __mmplayer_handle_missed_plugin(player);
6123 gst_object_unref(GST_OBJECT(pad));
6130 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6132 GstElement *decodebin = NULL;
6136 /* create decodebin */
6137 decodebin = gst_element_factory_make("decodebin", NULL);
6140 LOGE("fail to create decodebin");
6144 /* raw pad handling signal */
6145 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6146 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6148 /* no-more-pad pad handling signal */
6149 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6150 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6152 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6153 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6155 /* This signal is emitted when a pad for which there is no further possible
6156 decoding is added to the decodebin.*/
6157 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6158 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6160 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6161 before looking for any elements that can handle that stream.*/
6162 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6163 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6165 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6166 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6167 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6169 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6170 before looking for any elements that can handle that stream.*/
6171 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6172 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6174 /* This signal is emitted once decodebin has finished decoding all the data.*/
6175 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6176 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6178 /* This signal is emitted when a element is added to the bin.*/
6179 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6180 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6187 __mmplayer_gst_make_queue2(mmplayer_t *player)
6189 GstElement *queue2 = NULL;
6190 gint64 dur_bytes = 0L;
6191 mmplayer_gst_element_t *mainbin = NULL;
6192 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6195 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6197 mainbin = player->pipeline->mainbin;
6199 queue2 = gst_element_factory_make("queue2", "queue2");
6201 LOGE("failed to create buffering queue element");
6205 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6206 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6208 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6210 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6211 * skip the pull mode(file or ring buffering) setting. */
6212 if (dur_bytes > 0) {
6213 if (!g_strrstr(player->type_caps_str, "video/mpegts")) {
6214 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6215 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6221 _mm_player_streaming_set_queue2(player->streamer,
6225 (guint64)dur_bytes); /* no meaning at the moment */
6231 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6233 mmplayer_gst_element_t *mainbin = NULL;
6234 GstElement *decodebin = NULL;
6235 GstElement *queue2 = NULL;
6236 GstPad *sinkpad = NULL;
6237 GstPad *qsrcpad = NULL;
6240 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6242 mainbin = player->pipeline->mainbin;
6244 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6246 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6247 LOGW("need to check: muxed buffer is not null");
6250 queue2 = __mmplayer_gst_make_queue2(player);
6252 LOGE("failed to make queue2");
6256 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6257 LOGE("failed to add buffering queue");
6261 sinkpad = gst_element_get_static_pad(queue2, "sink");
6262 qsrcpad = gst_element_get_static_pad(queue2, "src");
6264 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6265 LOGE("failed to link [%s:%s]-[%s:%s]",
6266 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6270 if (!gst_element_sync_state_with_parent(queue2)) {
6271 LOGE("failed to sync queue2 state with parent");
6275 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6276 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6280 gst_object_unref(GST_OBJECT(sinkpad));
6284 /* create decodebin */
6285 decodebin = _mmplayer_gst_make_decodebin(player);
6287 LOGE("failed to make decodebin");
6291 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6292 LOGE("failed to add decodebin");
6296 /* to force caps on the decodebin element and avoid reparsing stuff by
6297 * typefind. It also avoids a deadlock in the way typefind activates pads in
6298 * the state change */
6299 g_object_set(decodebin, "sink-caps", caps, NULL);
6301 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6303 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6304 LOGE("failed to link [%s:%s]-[%s:%s]",
6305 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6309 gst_object_unref(GST_OBJECT(sinkpad));
6311 gst_object_unref(GST_OBJECT(qsrcpad));
6314 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6315 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6317 /* set decodebin property about buffer in streaming playback. *
6318 * in case of HLS/DASH, it does not need to have big buffer *
6319 * because it is kind of adaptive streaming. */
6320 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6321 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6322 gint high_percent = 0;
6324 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6325 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6327 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6329 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6331 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6332 "high-percent", high_percent,
6333 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6334 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6335 "max-size-buffers", 0, NULL); // disable or automatic
6338 if (!gst_element_sync_state_with_parent(decodebin)) {
6339 LOGE("failed to sync decodebin state with parent");
6350 gst_object_unref(GST_OBJECT(sinkpad));
6353 gst_object_unref(GST_OBJECT(qsrcpad));
6356 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6357 * You need to explicitly set elements to the NULL state before
6358 * dropping the final reference, to allow them to clean up.
6360 gst_element_set_state(queue2, GST_STATE_NULL);
6362 /* And, it still has a parent "player".
6363 * You need to let the parent manage the object instead of unreffing the object directly.
6365 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6366 LOGE("failed to remove queue2");
6367 gst_object_unref(queue2);
6373 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6374 * You need to explicitly set elements to the NULL state before
6375 * dropping the final reference, to allow them to clean up.
6377 gst_element_set_state(decodebin, GST_STATE_NULL);
6379 /* And, it still has a parent "player".
6380 * You need to let the parent manage the object instead of unreffing the object directly.
6383 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6384 LOGE("failed to remove decodebin");
6385 gst_object_unref(decodebin);
6394 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6398 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6399 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6401 LOGD("class : %s, mime : %s", factory_class, mime);
6403 /* add missing plugin */
6404 /* NOTE : msl should check missing plugin for image mime type.
6405 * Some motion jpeg clips can have playable audio track.
6406 * So, msl have to play audio after displaying popup written video format not supported.
6408 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6409 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6410 LOGD("not found demuxer");
6411 player->not_found_demuxer = TRUE;
6412 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6418 if (!g_strrstr(factory_class, "Demuxer")) {
6419 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6420 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6421 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6423 /* check that clip have multi tracks or not */
6424 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6425 LOGD("video plugin is already linked");
6427 LOGW("add VIDEO to missing plugin");
6428 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6429 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6431 } else if (g_str_has_prefix(mime, "audio")) {
6432 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6433 LOGD("audio plugin is already linked");
6435 LOGW("add AUDIO to missing plugin");
6436 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6437 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6445 return MM_ERROR_NONE;
6449 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6451 mmplayer_t *player = (mmplayer_t *)data;
6455 MMPLAYER_RETURN_IF_FAIL(player);
6457 /* remove fakesink. */
6458 if (!_mmplayer_gst_remove_fakesink(player,
6459 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6460 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6461 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6462 * source element are not same. To overcome this situation, this function will called
6463 * several places and several times. Therefore, this is not an error case.
6468 LOGD("[handle: %p] pipeline has completely constructed", player);
6470 if ((player->msg_posted == FALSE) &&
6471 (player->cmd >= MMPLAYER_COMMAND_START))
6472 __mmplayer_handle_missed_plugin(player);
6474 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6478 __mmplayer_check_profile(void)
6481 static int profile_tv = -1;
6483 if (__builtin_expect(profile_tv != -1, 1))
6486 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6487 switch (*profileName) {
6502 __mmplayer_get_next_uri(mmplayer_t *player)
6504 mmplayer_parse_profile_t profile;
6506 guint num_of_list = 0;
6509 num_of_list = g_list_length(player->uri_info.uri_list);
6510 uri_idx = player->uri_info.uri_idx;
6512 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6513 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6514 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6516 LOGW("next uri does not exist");
6520 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6521 LOGE("failed to parse profile");
6525 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6526 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6527 LOGW("uri type is not supported(%d)", profile.uri_type);
6531 LOGD("success to find next uri %d", uri_idx);
6535 if (!uri || uri_idx == num_of_list) {
6536 LOGE("failed to find next uri");
6540 player->uri_info.uri_idx = uri_idx;
6541 if (mm_player_set_attribute((MMHandleType)player, NULL,
6542 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6543 LOGE("failed to set attribute");
6547 if (!MMPLAYER_USE_DECODEBIN(player)) {
6548 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6549 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6550 "uri", profile.uri, NULL);
6553 SECURE_LOGD("next playback uri: %s", uri);
6558 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6560 #define REPEAT_COUNT_INFINITE -1
6561 #define REPEAT_COUNT_MIN 2
6562 #define ORIGINAL_URI_ONLY 1
6564 MMHandleType attrs = 0;
6568 guint num_of_uri = 0;
6569 int profile_tv = -1;
6573 LOGD("checking for gapless play option");
6575 if (player->build_audio_offload) {
6576 LOGE("offload path is not supportable.");
6580 if (player->pipeline->textbin) {
6581 LOGE("subtitle path is enabled. gapless play is not supported.");
6585 attrs = MMPLAYER_GET_ATTRS(player);
6587 LOGE("fail to get attributes.");
6591 mm_attrs_multiple_get(player->attrs, NULL,
6592 "content_video_found", &video,
6593 "profile_play_count", &count,
6594 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6596 /* gapless playback is not supported in case of video at TV profile. */
6597 profile_tv = __mmplayer_check_profile();
6598 if (profile_tv && video) {
6599 LOGW("not support video gapless playback");
6603 /* check repeat count in case of audio */
6605 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6606 LOGW("gapless is disabled");
6610 num_of_uri = g_list_length(player->uri_info.uri_list);
6611 if (!MMPLAYER_USE_DECODEBIN(player))
6612 player->gapless.running = TRUE;
6614 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6616 if (num_of_uri == ORIGINAL_URI_ONLY) {
6617 /* audio looping path */
6618 if (count >= REPEAT_COUNT_MIN) {
6619 /* decrease play count */
6620 /* we succeeded to rewind. update play count and then wait for next EOS */
6622 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6623 } else if (count != REPEAT_COUNT_INFINITE) {
6624 LOGD("there is no next uri and no repeat");
6628 if (!MMPLAYER_USE_DECODEBIN(player)) {
6629 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6630 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6631 "uri", player->profile.uri, NULL);
6634 LOGD("looping cnt %d", count);
6636 /* gapless playback path */
6637 if (!__mmplayer_get_next_uri(player)) {
6638 LOGE("failed to get next uri");
6645 LOGE("unable to play gapless path. EOS will be posted soon");
6650 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6652 GstPad *sinkpad = g_value_get_object (item);
6653 GstElement *element = GST_ELEMENT(user_data);
6654 if (!sinkpad || !element) {
6655 LOGE("invalid parameter");
6659 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6660 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6664 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6666 mmplayer_gst_element_t *sinkbin = NULL;
6667 main_element_id_e concatId = MMPLAYER_M_NUM;
6668 main_element_id_e sinkId = MMPLAYER_M_NUM;
6669 gboolean send_notice = FALSE;
6670 GstElement *element;
6674 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6676 LOGD("type %d", type);
6679 case MM_PLAYER_TRACK_TYPE_AUDIO:
6680 concatId = MMPLAYER_M_A_CONCAT;
6681 sinkId = MMPLAYER_A_BIN;
6682 sinkbin = player->pipeline->audiobin;
6684 case MM_PLAYER_TRACK_TYPE_VIDEO:
6685 concatId = MMPLAYER_M_V_CONCAT;
6686 sinkId = MMPLAYER_V_BIN;
6687 sinkbin = player->pipeline->videobin;
6690 case MM_PLAYER_TRACK_TYPE_TEXT:
6691 concatId = MMPLAYER_M_T_CONCAT;
6692 sinkId = MMPLAYER_T_BIN;
6693 sinkbin = player->pipeline->textbin;
6696 LOGE("requested type is not supportable");
6701 element = player->pipeline->mainbin[concatId].gst;
6705 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6706 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6707 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6708 if (srcpad && sinkpad) {
6709 /* after getting drained signal there is no data flows, so no need to do pad_block */
6710 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6711 gst_pad_unlink(srcpad, sinkpad);
6713 /* send custom event to sink pad to handle it at video sink */
6715 LOGD("send custom event to sinkpad");
6716 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6717 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6718 gst_pad_send_event(sinkpad, event);
6721 gst_object_unref(srcpad);
6722 gst_object_unref(sinkpad);
6725 LOGD("release concat request pad");
6726 /* release and unref requests pad from the selector */
6727 iter = gst_element_iterate_sink_pads(element);
6728 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6729 gst_iterator_resync(iter);
6730 gst_iterator_free(iter);
6736 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6738 mmplayer_track_t *selector = &player->track[type];
6739 mmplayer_gst_element_t *sinkbin = NULL;
6740 main_element_id_e selectorId = MMPLAYER_M_NUM;
6741 main_element_id_e sinkId = MMPLAYER_M_NUM;
6742 GstPad *srcpad = NULL;
6743 GstPad *sinkpad = NULL;
6744 gboolean send_notice = FALSE;
6747 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6749 LOGD("type %d", type);
6752 case MM_PLAYER_TRACK_TYPE_AUDIO:
6753 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6754 sinkId = MMPLAYER_A_BIN;
6755 sinkbin = player->pipeline->audiobin;
6757 case MM_PLAYER_TRACK_TYPE_VIDEO:
6758 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6759 sinkId = MMPLAYER_V_BIN;
6760 sinkbin = player->pipeline->videobin;
6763 case MM_PLAYER_TRACK_TYPE_TEXT:
6764 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6765 sinkId = MMPLAYER_T_BIN;
6766 sinkbin = player->pipeline->textbin;
6769 LOGE("requested type is not supportable");
6774 if (player->pipeline->mainbin[selectorId].gst) {
6777 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6779 if (selector->event_probe_id != 0)
6780 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6781 selector->event_probe_id = 0;
6783 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6784 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6786 if (srcpad && sinkpad) {
6787 /* after getting drained signal there is no data flows, so no need to do pad_block */
6788 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6789 gst_pad_unlink(srcpad, sinkpad);
6791 /* send custom event to sink pad to handle it at video sink */
6793 LOGD("send custom event to sinkpad");
6794 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6795 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6796 gst_pad_send_event(sinkpad, event);
6800 gst_object_unref(sinkpad);
6803 gst_object_unref(srcpad);
6806 LOGD("selector release");
6808 /* release and unref requests pad from the selector */
6809 for (n = 0; n < selector->streams->len; n++) {
6810 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6811 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6814 g_ptr_array_set_size(selector->streams, 0);
6816 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6817 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6818 player->pipeline->mainbin[selectorId].gst)) {
6819 LOGE("failed to remove selector");
6820 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6823 player->pipeline->mainbin[selectorId].gst = NULL;
6831 __mmplayer_deactivate_old_path(mmplayer_t *player)
6834 MMPLAYER_RETURN_IF_FAIL(player);
6836 if (MMPLAYER_USE_DECODEBIN(player)) {
6837 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6838 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6839 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6840 LOGE("deactivate selector error");
6844 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6845 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6846 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6847 LOGE("deactivate concat error");
6852 _mmplayer_track_destroy(player);
6853 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6855 if (player->streamer) {
6856 _mm_player_streaming_initialize(player->streamer, FALSE);
6857 _mm_player_streaming_destroy(player->streamer);
6858 player->streamer = NULL;
6861 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6867 if (!player->msg_posted) {
6868 MMMessageParamType msg = {0,};
6871 msg.code = MM_ERROR_PLAYER_INTERNAL;
6872 LOGE("gapless_uri_play> deactivate error");
6874 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6875 player->msg_posted = TRUE;
6881 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6883 int result = MM_ERROR_NONE;
6884 mmplayer_t *player = (mmplayer_t *)hplayer;
6887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6888 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6890 if (mm_player_set_attribute(hplayer, NULL,
6891 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6892 LOGE("failed to set attribute");
6893 result = MM_ERROR_PLAYER_INTERNAL;
6895 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6896 LOGE("failed to add the original uri in the uri list.");
6904 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6906 mmplayer_t *player = (mmplayer_t *)hplayer;
6907 guint num_of_list = 0;
6911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6912 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6914 if (player->pipeline && player->pipeline->textbin) {
6915 LOGE("subtitle path is enabled.");
6916 return MM_ERROR_PLAYER_INVALID_STATE;
6919 num_of_list = g_list_length(player->uri_info.uri_list);
6921 if (is_first_path) {
6922 if (num_of_list == 0) {
6923 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6924 SECURE_LOGD("add original path : %s", uri);
6926 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6927 player->uri_info.uri_list = g_list_prepend(
6928 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6929 SECURE_LOGD("change original path : %s", uri);
6932 MMHandleType attrs = 0;
6933 attrs = MMPLAYER_GET_ATTRS(player);
6935 if (num_of_list == 0) {
6936 char *original_uri = NULL;
6939 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6941 if (!original_uri) {
6942 LOGE("there is no original uri.");
6943 return MM_ERROR_PLAYER_INVALID_STATE;
6946 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6947 player->uri_info.uri_idx = 0;
6949 SECURE_LOGD("add original path at first : %s", original_uri);
6953 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6954 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6958 return MM_ERROR_NONE;
6962 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6964 mmplayer_t *player = (mmplayer_t *)hplayer;
6965 char *next_uri = NULL;
6966 guint num_of_list = 0;
6969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6971 num_of_list = g_list_length(player->uri_info.uri_list);
6973 if (num_of_list > 0) {
6974 gint uri_idx = player->uri_info.uri_idx;
6976 if (uri_idx < num_of_list - 1)
6981 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6982 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6984 *uri = g_strdup(next_uri);
6988 return MM_ERROR_NONE;
6992 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6993 GstCaps *caps, gpointer data)
6995 mmplayer_t *player = (mmplayer_t *)data;
6996 const gchar *klass = NULL;
6997 const gchar *mime = NULL;
6998 gchar *caps_str = NULL;
7000 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7001 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7002 caps_str = gst_caps_to_string(caps);
7004 LOGW("unknown type of caps : %s from %s",
7005 caps_str, GST_ELEMENT_NAME(elem));
7007 MMPLAYER_FREEIF(caps_str);
7009 /* There is no available codec. */
7010 _mmplayer_update_not_supported_codec_info(player, klass, mime);
7014 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
7015 GstCaps *caps, gpointer data)
7017 mmplayer_t *player = (mmplayer_t *)data;
7018 const char *mime = NULL;
7019 gboolean ret = TRUE;
7021 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7022 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7024 if (g_str_has_prefix(mime, "audio")) {
7025 GstStructure *caps_structure = NULL;
7026 gint samplerate = 0;
7028 gchar *caps_str = NULL;
7030 caps_structure = gst_caps_get_structure(caps, 0);
7031 gst_structure_get_int(caps_structure, "rate", &samplerate);
7032 gst_structure_get_int(caps_structure, "channels", &channels);
7034 if ((channels > 0 && samplerate == 0)) {
7035 LOGD("exclude audio...");
7039 caps_str = gst_caps_to_string(caps);
7040 /* set it directly because not sent by TAG */
7041 if (g_strrstr(caps_str, "mobile-xmf"))
7042 mm_player_set_attribute((MMHandleType)player, NULL,
7043 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7045 MMPLAYER_FREEIF(caps_str);
7046 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7047 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7048 LOGD("video is already linked, allow the stream switch");
7051 LOGD("video is already linked");
7055 LOGD("found new stream");
7062 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7064 gboolean ret = FALSE;
7065 GDBusConnection *conn = NULL;
7067 GVariant *result = NULL;
7068 const gchar *dbus_device_type = NULL;
7069 const gchar *dbus_ret = NULL;
7072 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7074 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7079 result = g_dbus_connection_call_sync(conn,
7080 "org.pulseaudio.Server",
7081 "/org/pulseaudio/StreamManager",
7082 "org.pulseaudio.StreamManager",
7083 "GetCurrentMediaRoutingPath",
7084 g_variant_new("(s)", "out"),
7085 G_VARIANT_TYPE("(ss)"),
7086 G_DBUS_CALL_FLAGS_NONE,
7090 if (!result || err) {
7091 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7096 /* device type is listed in stream-map.json at mmfw-sysconf */
7097 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7099 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7100 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7103 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7104 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7105 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7106 LOGD("audio offload is supportable");
7112 LOGD("audio offload is not supportable");
7115 g_variant_unref(result);
7117 g_object_unref(conn);
7122 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7124 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7125 gint64 position = 0;
7127 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7128 player->pipeline && player->pipeline->mainbin);
7130 MMPLAYER_CMD_LOCK(player);
7131 current_state = MMPLAYER_CURRENT_STATE(player);
7133 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7134 LOGW("getting current position failed in paused");
7136 _mmplayer_unrealize((MMHandleType)player);
7137 _mmplayer_realize((MMHandleType)player);
7139 _mmplayer_set_position((MMHandleType)player, position);
7141 /* async not to be blocked in streaming case */
7142 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7144 _mmplayer_pause((MMHandleType)player);
7146 if (current_state == MM_PLAYER_STATE_PLAYING)
7147 _mmplayer_start((MMHandleType)player);
7148 MMPLAYER_CMD_UNLOCK(player);
7150 LOGD("rebuilding audio pipeline is completed.");
7153 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7155 mmplayer_t *player = (mmplayer_t *)user_data;
7156 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7157 gboolean is_supportable = FALSE;
7159 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7160 LOGW("failed to get device type");
7162 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7164 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7165 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7166 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7167 LOGD("ignore this dev connected info");
7171 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7172 if (player->build_audio_offload == is_supportable) {
7173 LOGD("keep current pipeline without re-building");
7177 /* rebuild pipeline */
7178 LOGD("re-build pipeline - offload: %d", is_supportable);
7179 player->build_audio_offload = FALSE;
7180 __mmplayer_rebuild_audio_pipeline(player);
7186 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7188 unsigned int id = 0;
7190 if (player->audio_device_cb_id != 0) {
7191 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7195 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7196 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7197 LOGD("added device connected cb (%u)", id);
7198 player->audio_device_cb_id = id;
7200 LOGW("failed to add device connected cb");
7207 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7209 mmplayer_t *player = (mmplayer_t *)hplayer;
7212 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7213 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7215 *activated = player->build_audio_offload;
7217 LOGD("offload activated : %d", (int)*activated);
7220 return MM_ERROR_NONE;
7224 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7227 this function need to be updated according to the supported media format
7228 @see player->ini.audio_offload_media_format */
7230 if (__mmplayer_is_only_mp3_type(player->type_caps_str)) {
7231 LOGD("offload supportable media format type");
7239 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7241 gboolean ret = FALSE;
7242 GstElementFactory *factory = NULL;
7245 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7247 LOGD("current stream : %s, sink: %s", player->type_caps_str, player->ini.audio_offload_sink_element);
7248 if (!__mmplayer_is_offload_supported_type(player))
7251 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7252 LOGD("there is no audio offload sink");
7256 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7257 LOGW("there is no audio device type to support offload");
7261 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7263 LOGW("there is no installed audio offload sink element");
7266 gst_object_unref(factory);
7268 if (_mmplayer_acquire_hw_resource(player,
7269 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7270 LOGE("failed to acquire audio offload decoder resource");
7274 if (!__mmplayer_add_audio_device_connected_cb(player))
7277 if (!__mmplayer_is_audio_offload_device_type(player))
7280 LOGD("audio offload can be built");
7285 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7291 static GstAutoplugSelectResult
7292 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7294 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7295 int audio_offload = 0;
7297 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7298 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7300 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7301 LOGD("expose audio path to build offload output path");
7302 player->build_audio_offload = TRUE;
7303 /* update codec info */
7304 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7305 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7306 player->audiodec_linked = 1;
7308 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7312 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7313 And need to consider the multi-track audio content.
7314 There is no HW audio decoder in public. */
7316 /* set stream information */
7317 if (!player->audiodec_linked)
7318 _mmplayer_set_audio_attrs(player, caps);
7320 /* update codec info */
7321 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7322 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7323 player->audiodec_linked = 1;
7325 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7327 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7328 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7330 /* mark video decoder for acquire */
7331 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7332 LOGW("video decoder resource is already acquired, skip it.");
7333 ret = GST_AUTOPLUG_SELECT_SKIP;
7337 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7338 LOGE("failed to acquire video decoder resource");
7339 ret = GST_AUTOPLUG_SELECT_SKIP;
7342 player->interrupted_by_resource = FALSE;
7345 /* update codec info */
7346 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7347 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7348 player->videodec_linked = 1;
7356 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7357 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7359 #define DEFAULT_IDX 0xFFFF
7360 #define MIN_FACTORY_NUM 2
7361 mmplayer_t *player = (mmplayer_t *)data;
7362 GValueArray *new_factories = NULL;
7363 GValue val = { 0, };
7364 GstElementFactory *factory = NULL;
7365 const gchar *klass = NULL;
7366 gchar *factory_name = NULL;
7367 guint hw_dec_idx = DEFAULT_IDX;
7368 guint first_sw_dec_idx = DEFAULT_IDX;
7369 guint last_sw_dec_idx = DEFAULT_IDX;
7370 guint new_pos = DEFAULT_IDX;
7371 guint rm_pos = DEFAULT_IDX;
7372 int audio_codec_type;
7373 int video_codec_type;
7374 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7376 if (factories->n_values < MIN_FACTORY_NUM)
7379 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7380 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7383 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7385 for (int i = 0 ; i < factories->n_values ; i++) {
7386 gchar *hw_dec_info = NULL;
7387 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7389 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7391 LOGW("failed to get factory object");
7394 klass = gst_element_factory_get_klass(factory);
7395 factory_name = GST_OBJECT_NAME(factory);
7398 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7400 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7401 if (!player->need_audio_dec_sorting) {
7402 LOGD("sorting is not required");
7405 codec_type = audio_codec_type;
7406 hw_dec_info = player->ini.audiocodec_element_hw;
7407 sw_dec_info = player->ini.audiocodec_element_sw;
7408 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7409 if (!player->need_video_dec_sorting) {
7410 LOGD("sorting is not required");
7413 codec_type = video_codec_type;
7414 hw_dec_info = player->ini.videocodec_element_hw;
7415 sw_dec_info = player->ini.videocodec_element_sw;
7420 if (g_strrstr(factory_name, hw_dec_info)) {
7423 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7424 if (strstr(factory_name, sw_dec_info[j])) {
7425 last_sw_dec_idx = i;
7426 if (first_sw_dec_idx == DEFAULT_IDX) {
7427 first_sw_dec_idx = i;
7432 if (first_sw_dec_idx == DEFAULT_IDX)
7433 LOGW("unknown codec %s", factory_name);
7437 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7440 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7441 if (hw_dec_idx < first_sw_dec_idx)
7443 new_pos = first_sw_dec_idx;
7444 rm_pos = hw_dec_idx + 1;
7445 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7446 if (last_sw_dec_idx < hw_dec_idx)
7448 new_pos = last_sw_dec_idx + 1;
7449 rm_pos = hw_dec_idx;
7454 /* change position - insert H/W decoder according to the new position */
7455 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7457 LOGW("failed to get factory object");
7460 new_factories = g_value_array_copy(factories);
7461 g_value_init (&val, G_TYPE_OBJECT);
7462 g_value_set_object (&val, factory);
7463 g_value_array_insert(new_factories, new_pos, &val);
7464 g_value_unset (&val);
7465 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7467 for (int i = 0 ; i < new_factories->n_values ; i++) {
7468 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7470 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7471 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7473 LOGE("[Re-arranged] failed to get factory object");
7476 return new_factories;
7480 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7481 GstCaps *caps, GstElementFactory *factory, gpointer data)
7483 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7484 mmplayer_t *player = (mmplayer_t *)data;
7486 gchar *factory_name = NULL;
7487 gchar *caps_str = NULL;
7488 const gchar *klass = NULL;
7491 factory_name = GST_OBJECT_NAME(factory);
7492 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7493 caps_str = gst_caps_to_string(caps);
7495 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7497 /* store type string */
7498 if (player->type_caps_str == NULL) {
7499 player->type_caps_str = gst_caps_to_string(caps);
7500 __mmplayer_update_content_type_info(player);
7503 /* filtering exclude keyword */
7504 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7505 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7506 LOGW("skipping [%s] by exclude keyword [%s]",
7507 factory_name, player->ini.exclude_element_keyword[idx]);
7509 result = GST_AUTOPLUG_SELECT_SKIP;
7514 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7515 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7516 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7517 factory_name, player->ini.unsupported_codec_keyword[idx]);
7518 result = GST_AUTOPLUG_SELECT_SKIP;
7523 /* exclude webm format */
7524 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7525 * because webm format is not supportable.
7526 * If webm is disabled in "autoplug-continue", there is no state change
7527 * failure or error because the decodebin will expose the pad directly.
7528 * It make MSL invoke _prepare_async_callback.
7529 * So, we need to disable webm format in "autoplug-select" */
7530 if (caps_str && strstr(caps_str, "webm")) {
7531 LOGW("webm is not supported");
7532 result = GST_AUTOPLUG_SELECT_SKIP;
7536 /* check factory class for filtering */
7537 /* NOTE : msl don't need to use image plugins.
7538 * So, those plugins should be skipped for error handling.
7540 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7541 LOGD("skipping [%s] by not required", factory_name);
7542 result = GST_AUTOPLUG_SELECT_SKIP;
7546 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7547 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7548 // TO CHECK : subtitle if needed, add subparse exception.
7549 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7550 result = GST_AUTOPLUG_SELECT_SKIP;
7554 if (g_strrstr(factory_name, "mpegpsdemux")) {
7555 LOGD("skipping PS container - not support");
7556 result = GST_AUTOPLUG_SELECT_SKIP;
7560 if (g_strrstr(factory_name, "mssdemux"))
7561 player->smooth_streaming = TRUE;
7563 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7564 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7567 GstStructure *str = NULL;
7569 /* parsebin in adaptivedemux get error if there is no parser */
7570 if ((!g_strrstr(GST_ELEMENT_NAME(bin), "parsebin")) ||
7571 ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player)))) {
7572 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7574 /* don't make video because of not required */
7575 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7576 (!player->set_mode.video_export)) {
7577 LOGD("no need video decoding, expose pad");
7578 result = GST_AUTOPLUG_SELECT_EXPOSE;
7583 /* get w/h for omx state-tune */
7584 /* FIXME: deprecated? */
7585 str = gst_caps_get_structure(caps, 0);
7586 gst_structure_get_int(str, "width", &width);
7589 if (player->v_stream_caps) {
7590 gst_caps_unref(player->v_stream_caps);
7591 player->v_stream_caps = NULL;
7594 player->v_stream_caps = gst_caps_copy(caps);
7595 LOGD("take caps for video state tune");
7596 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7600 if (g_strrstr(klass, "Codec/Decoder")) {
7601 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7602 if (result != GST_AUTOPLUG_SELECT_TRY) {
7603 LOGW("skip add decoder");
7609 MMPLAYER_FREEIF(caps_str);
7615 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7618 int ret = MM_ERROR_NONE;
7619 mmplayer_t *player = (mmplayer_t *)data;
7620 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7621 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7622 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7625 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7627 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7629 if (MMPLAYER_USE_DECODEBIN(player))
7632 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7635 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7637 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7639 LOGD("remove videobin");
7640 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7641 GST_STATE_NULL, FALSE, timeout);
7642 if (ret != MM_ERROR_NONE) {
7643 LOGE("fail to change state of videobin to NULL");
7647 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7648 LOGE("failed to remove videobin");
7649 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7652 LOGD("remove concat");
7653 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7654 GST_STATE_NULL, FALSE, timeout);
7655 if (ret != MM_ERROR_NONE) {
7656 LOGE("fail to change state of concat to NULL");
7660 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7661 LOGE("failed to remove video concat");
7662 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7665 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7666 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7667 MMPLAYER_FREEIF(player->pipeline->videobin);
7669 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7670 if (ret != MM_ERROR_NONE)
7671 LOGE("failed to release overlay resources");
7673 player->videodec_linked = 0;
7675 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7680 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7682 mmplayer_t *player = (mmplayer_t *)data;
7685 MMPLAYER_RETURN_IF_FAIL(player);
7687 LOGD("got about to finish signal");
7689 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7690 LOGW("Fail to get cmd lock");
7694 if (!__mmplayer_verify_gapless_play_path(player)) {
7695 LOGD("decoding is finished.");
7696 if (MMPLAYER_USE_DECODEBIN(player)) {
7697 MMPLAYER_CMD_UNLOCK(player);
7702 if (MMPLAYER_USE_DECODEBIN(player)) {
7703 _mmplayer_set_reconfigure_state(player, TRUE);
7704 MMPLAYER_CMD_UNLOCK(player);
7705 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7706 __mmplayer_deactivate_old_path(player);
7708 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7709 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7710 MMPLAYER_CMD_UNLOCK(player);
7717 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7719 mmplayer_t *player = (mmplayer_t *)data;
7720 GstIterator *iter = NULL;
7721 GValue item = { 0, };
7723 gboolean done = FALSE;
7724 gboolean is_all_drained = TRUE;
7727 MMPLAYER_RETURN_IF_FAIL(player);
7729 LOGD("got drained signal");
7731 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7732 LOGW("Fail to get cmd lock");
7736 if (!__mmplayer_verify_gapless_play_path(player)) {
7737 LOGD("decoding is finished.");
7738 MMPLAYER_CMD_UNLOCK(player);
7742 _mmplayer_set_reconfigure_state(player, TRUE);
7743 MMPLAYER_CMD_UNLOCK(player);
7745 /* check decodebin src pads whether they received EOS or not */
7746 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7749 switch (gst_iterator_next(iter, &item)) {
7750 case GST_ITERATOR_OK:
7751 pad = g_value_get_object(&item);
7752 if (pad && !GST_PAD_IS_EOS(pad)) {
7753 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7754 is_all_drained = FALSE;
7757 g_value_reset(&item);
7759 case GST_ITERATOR_RESYNC:
7760 gst_iterator_resync(iter);
7762 case GST_ITERATOR_ERROR:
7763 case GST_ITERATOR_DONE:
7768 g_value_unset(&item);
7769 gst_iterator_free(iter);
7771 if (!is_all_drained) {
7772 LOGD("Wait util the all pads get EOS.");
7777 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7778 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7780 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7781 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7782 __mmplayer_deactivate_old_path(player);
7788 _mmplayer_gst_element_added(GstBin *bin, GstElement *element, gpointer data)
7790 mmplayer_t *player = (mmplayer_t *)data;
7791 const gchar *klass = NULL;
7792 gchar *factory_name = NULL;
7794 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7795 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7797 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7799 if (__mmplayer_add_dump_buffer_probe(player, element))
7800 LOGD("add buffer probe");
7802 if (g_strrstr(klass, "Decoder")) {
7803 if (g_strrstr(klass, "Audio")) {
7804 player->audio_decoders = g_list_append(player->audio_decoders,
7805 g_strdup(GST_ELEMENT_NAME(element)));
7807 /* update codec info */
7808 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7809 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7810 player->audiodec_linked = 1;
7811 } else if (g_strrstr(klass, "Video")) {
7812 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7813 /* update codec info */
7814 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7815 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7816 player->videodec_linked = 1;
7819 GstPad *srcpad = gst_element_get_static_pad(video_parse, "src");
7821 GstCaps *caps = NULL;
7822 GstStructure *str = NULL;
7823 const gchar *name = NULL;
7824 gboolean caps_ret = TRUE;
7826 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(srcpad, caps, str, name, caps_ret);
7827 if (caps_ret && str) {
7828 const gchar *stream_format = gst_structure_get_string(str, "stream-format");
7829 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7830 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7831 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7832 LOGD("Send SPS and PPS Insertion every IDR frame");
7837 gst_caps_unref(caps);
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);
8074 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
8076 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8077 if (!subtitle_uri || (strlen(subtitle_uri) == 0)) {
8082 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
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 result = MM_ERROR_PLAYER_INTERNAL;
8363 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8367 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
8368 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
8369 if (GST_IS_ELEMENT(text_sink)) {
8370 if (gst_element_send_event(text_sink, event))
8371 LOGD("sending event[%s] to subtitle sink element [%s] success!",
8372 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8374 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
8375 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8378 _mmplayer_gst_send_event_to_sink(player, event);
8381 /* sync state with current pipeline */
8382 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8383 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8384 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8386 return MM_ERROR_NONE;
8389 /* release text pipeline resource */
8390 player->textsink_linked = 0;
8392 /* release signal */
8393 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8395 /* release textbin with it's children */
8396 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8397 MMPLAYER_FREEIF(player->pipeline->textbin);
8398 player->pipeline->textbin = NULL;
8400 /* release subtitle elem */
8401 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8402 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8408 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8410 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8411 GstState current_state = GST_STATE_VOID_PENDING;
8413 MMHandleType attrs = 0;
8414 mmplayer_gst_element_t *mainbin = NULL;
8415 mmplayer_gst_element_t *textbin = NULL;
8417 gchar *subtitle_uri = NULL;
8418 int result = MM_ERROR_NONE;
8419 const gchar *charset = NULL;
8423 /* check player handle */
8424 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8426 player->pipeline->mainbin &&
8427 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8430 mainbin = player->pipeline->mainbin;
8431 textbin = player->pipeline->textbin;
8433 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8434 if (current_state < GST_STATE_READY) {
8435 result = MM_ERROR_PLAYER_INVALID_STATE;
8436 LOGE("Pipeline is not in proper state");
8440 attrs = MMPLAYER_GET_ATTRS(player);
8442 LOGE("cannot get content attribute");
8443 result = MM_ERROR_PLAYER_INTERNAL;
8447 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8448 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8449 LOGE("subtitle uri is not proper filepath");
8450 result = MM_ERROR_PLAYER_INVALID_URI;
8454 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8455 LOGE("failed to get storage info of subtitle path");
8456 result = MM_ERROR_PLAYER_INVALID_URI;
8460 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8461 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8463 if (!strcmp(filepath, subtitle_uri)) {
8464 LOGD("subtitle path is not changed");
8467 if (mm_player_set_attribute((MMHandleType)player, NULL,
8468 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8469 LOGE("failed to set attribute");
8474 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8475 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8476 player->subtitle_language_list = NULL;
8477 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8479 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8480 if (ret != GST_STATE_CHANGE_SUCCESS) {
8481 LOGE("failed to change state of textbin to READY");
8482 result = MM_ERROR_PLAYER_INTERNAL;
8486 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8487 if (ret != GST_STATE_CHANGE_SUCCESS) {
8488 LOGE("failed to change state of subparse to READY");
8489 result = MM_ERROR_PLAYER_INTERNAL;
8493 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8494 if (ret != GST_STATE_CHANGE_SUCCESS) {
8495 LOGE("failed to change state of filesrc to READY");
8496 result = MM_ERROR_PLAYER_INTERNAL;
8500 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8502 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8504 charset = _mmplayer_get_charset(filepath);
8506 LOGD("detected charset is %s", charset);
8507 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8510 result = _mmplayer_sync_subtitle_pipeline(player);
8517 /* API to switch between external subtitles */
8519 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8521 int result = MM_ERROR_NONE;
8522 mmplayer_t *player = (mmplayer_t *)hplayer;
8527 /* check player handle */
8528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8530 /* filepath can be null in idle state */
8532 /* check file path */
8533 if ((path = strstr(filepath, "file://")))
8534 result = _mmplayer_exist_file_path(path + 7);
8536 result = _mmplayer_exist_file_path(filepath);
8538 if (result != MM_ERROR_NONE) {
8539 LOGE("invalid subtitle path 0x%X", result);
8540 return result; /* file not found or permission denied */
8544 if (!player->pipeline) {
8546 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8547 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8548 LOGE("failed to set attribute");
8549 return MM_ERROR_PLAYER_INTERNAL;
8552 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8553 /* check filepath */
8554 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8556 if (!__mmplayer_check_subtitle(player)) {
8557 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8558 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8559 LOGE("failed to set attribute");
8560 return MM_ERROR_PLAYER_INTERNAL;
8563 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8564 LOGE("fail to create text pipeline");
8565 return MM_ERROR_PLAYER_INTERNAL;
8568 result = _mmplayer_sync_subtitle_pipeline(player);
8570 result = __mmplayer_change_external_subtitle_language(player, filepath);
8573 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8574 player->is_external_subtitle_added_now = TRUE;
8576 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8577 if (!player->subtitle_language_list) {
8578 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8579 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8580 LOGW("subtitle language list is not updated yet");
8582 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8584 player->is_external_subtitle_present = TRUE;
8591 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8593 guint active_idx = 0;
8594 GstStream *stream = NULL;
8595 GList *streams = NULL;
8596 GstCaps *caps = NULL;
8599 LOGD("Switching Streams... type: %d, index: %d", type, index);
8601 player->track[type].active_track_index = index;
8603 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8604 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8605 LOGD("track type:%d, total: %d, active: %d", i,
8606 player->track[i].total_track_num, player->track[i].active_track_index);
8607 if (player->track[i].total_track_num > 0 &&
8608 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8609 active_idx = player->track[i].active_track_index;
8610 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8611 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8612 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8614 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8615 caps = gst_stream_get_caps(stream);
8617 _mmplayer_set_audio_attrs(player, caps);
8618 gst_caps_unref(caps);
8625 LOGD("send select stream event");
8626 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8627 gst_event_new_select_streams(streams));
8628 g_list_free(streams);
8631 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8632 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8633 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8635 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8636 pos_nsec = player->last_position;
8638 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8640 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8641 player->playback_rate, GST_FORMAT_TIME,
8642 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8643 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8644 LOGW("failed to seek");
8645 return MM_ERROR_PLAYER_INTERNAL;
8650 return MM_ERROR_NONE;
8654 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8656 int result = MM_ERROR_NONE;
8657 gchar *change_pad_name = NULL;
8658 GstPad *sinkpad = NULL;
8659 mmplayer_gst_element_t *mainbin = NULL;
8660 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8661 GstCaps *caps = NULL;
8662 gint total_track_num = 0;
8666 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8667 MM_ERROR_PLAYER_NOT_INITIALIZED);
8669 LOGD("Change Track(%d) to %d", type, index);
8671 mainbin = player->pipeline->mainbin;
8673 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8674 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8675 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8676 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8678 /* Changing Video Track is not supported. */
8679 LOGE("Track Type Error");
8683 if (mainbin[elem_idx].gst == NULL) {
8684 result = MM_ERROR_PLAYER_NO_OP;
8685 LOGD("Req track doesn't exist");
8689 total_track_num = player->track[type].total_track_num;
8690 if (total_track_num <= 0) {
8691 result = MM_ERROR_PLAYER_NO_OP;
8692 LOGD("Language list is not available");
8696 if ((index < 0) || (index >= total_track_num)) {
8697 result = MM_ERROR_INVALID_ARGUMENT;
8698 LOGD("Not a proper index : %d", index);
8702 /*To get the new pad from the selector*/
8703 change_pad_name = g_strdup_printf("sink_%u", index);
8704 if (change_pad_name == NULL) {
8705 result = MM_ERROR_PLAYER_INTERNAL;
8706 LOGD("Pad does not exists");
8710 LOGD("new active pad name: %s", change_pad_name);
8712 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8713 if (sinkpad == NULL) {
8714 LOGD("sinkpad is NULL");
8715 result = MM_ERROR_PLAYER_INTERNAL;
8719 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8720 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8722 caps = gst_pad_get_current_caps(sinkpad);
8723 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8726 gst_object_unref(sinkpad);
8728 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8729 _mmplayer_set_audio_attrs(player, caps);
8732 gst_caps_unref(caps);
8735 MMPLAYER_FREEIF(change_pad_name);
8740 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8742 int result = MM_ERROR_NONE;
8743 mmplayer_t *player = NULL;
8744 mmplayer_gst_element_t *mainbin = NULL;
8746 gint current_active_index = 0;
8748 GstState current_state = GST_STATE_VOID_PENDING;
8753 player = (mmplayer_t *)hplayer;
8754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8755 MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_PLAYER_NOT_INITIALIZED);
8757 if (!player->pipeline) {
8758 LOGE("Track %d pre setting -> %d", type, index);
8760 player->track[type].active_track_index = index;
8764 mainbin = player->pipeline->mainbin;
8766 current_active_index = player->track[type].active_track_index;
8768 /*If index is same as running index no need to change the pad*/
8769 if (current_active_index == index)
8772 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8773 result = MM_ERROR_PLAYER_INVALID_STATE;
8777 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8778 if (current_state < GST_STATE_PAUSED) {
8779 result = MM_ERROR_PLAYER_INVALID_STATE;
8780 LOGW("Pipeline not in proper state");
8784 if (MMPLAYER_USE_DECODEBIN(player))
8785 result = __mmplayer_change_selector_pad(player, type, index);
8787 result = __mmplayer_switch_stream(player, type, index);
8789 if (result != MM_ERROR_NONE) {
8790 LOGE("failed to change track");
8794 player->track[type].active_track_index = index;
8796 if (MMPLAYER_USE_DECODEBIN(player)) {
8797 GstEvent *event = NULL;
8798 if (current_state == GST_STATE_PLAYING) {
8799 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8800 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8801 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8803 _mmplayer_gst_send_event_to_sink(player, event);
8805 result = MM_ERROR_PLAYER_INTERNAL;
8816 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8818 mmplayer_t *player = (mmplayer_t *)hplayer;
8822 /* check player handle */
8823 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8825 *silent = player->set_mode.subtitle_off;
8827 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8831 return MM_ERROR_NONE;
8835 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8837 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8838 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8840 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8841 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8845 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8846 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8847 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8848 mmplayer_dump_t *dump_s;
8849 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8850 if (dump_s == NULL) {
8851 LOGE("malloc fail");
8855 dump_s->dump_element_file = NULL;
8856 dump_s->dump_pad = NULL;
8857 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8859 if (dump_s->dump_pad) {
8860 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8861 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]);
8862 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8863 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);
8864 /* add list for removed buffer probe and close FILE */
8865 player->dump_list = g_list_append(player->dump_list, dump_s);
8866 LOGD("%s sink pad added buffer probe for dump", factory_name);
8869 MMPLAYER_FREEIF(dump_s);
8870 LOGE("failed to get %s sink pad added", factory_name);
8877 static GstPadProbeReturn
8878 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8880 FILE *dump_data = (FILE *)u_data;
8882 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8883 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8885 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8887 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8889 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8891 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8893 gst_buffer_unmap(buffer, &probe_info);
8895 return GST_PAD_PROBE_OK;
8899 __mmplayer_release_dump_list(GList *dump_list)
8901 GList *d_list = dump_list;
8906 for (; d_list; d_list = g_list_next(d_list)) {
8907 mmplayer_dump_t *dump_s = d_list->data;
8908 if (dump_s->dump_pad) {
8909 if (dump_s->probe_handle_id)
8910 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8911 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8913 if (dump_s->dump_element_file) {
8914 fclose(dump_s->dump_element_file);
8915 dump_s->dump_element_file = NULL;
8917 MMPLAYER_FREEIF(dump_s);
8919 g_list_free(dump_list);
8924 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8926 mmplayer_t *player = (mmplayer_t *)hplayer;
8930 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8931 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8933 *exist = (bool)player->has_closed_caption;
8937 return MM_ERROR_NONE;
8941 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8946 LOGD("unref internal gst buffer %p", buffer);
8948 gst_buffer_unref((GstBuffer *)buffer);
8955 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8957 mmplayer_t *player = (mmplayer_t *)hplayer;
8961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8962 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8964 if (MMPLAYER_IS_STREAMING(player))
8965 *timeout = (int)player->ini.live_state_change_timeout;
8967 *timeout = (int)player->ini.localplayback_state_change_timeout;
8969 LOGD("timeout = %d", *timeout);
8972 return MM_ERROR_NONE;
8976 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8980 MMPLAYER_RETURN_IF_FAIL(player);
8982 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8984 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8985 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8986 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8987 player->storage_info[i].id = -1;
8988 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8990 if (path_type != MMPLAYER_PATH_MAX)
8999 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
9001 int ret = MM_ERROR_NONE;
9002 mmplayer_t *player = (mmplayer_t *)hplayer;
9003 MMMessageParamType msg_param = {0, };
9006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9008 LOGW("state changed storage %d:%d", id, state);
9010 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
9011 return MM_ERROR_NONE;
9013 /* FIXME: text path should be handled separately. */
9014 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
9015 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9016 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
9017 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9018 LOGW("external storage is removed");
9020 if (player->msg_posted == FALSE) {
9021 memset(&msg_param, 0, sizeof(MMMessageParamType));
9022 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9023 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9024 player->msg_posted = TRUE;
9027 /* unrealize the player */
9028 ret = _mmplayer_unrealize(hplayer);
9029 if (ret != MM_ERROR_NONE)
9030 LOGE("failed to unrealize");
9038 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9040 int ret = MM_ERROR_NONE;
9041 mmplayer_t *player = (mmplayer_t *)hplayer;
9042 int idx = 0, total = 0;
9043 gchar *result = NULL, *tmp = NULL;
9046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9047 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9049 total = *num = g_list_length(player->adaptive_info.var_list);
9051 LOGW("There is no stream variant info.");
9055 result = g_strdup("");
9056 for (idx = 0 ; idx < total ; idx++) {
9057 stream_variant_t *v_data = NULL;
9058 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9061 gchar data[64] = {0};
9062 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9064 tmp = g_strconcat(result, data, NULL);
9068 LOGW("There is no variant data in %d", idx);
9073 *var_info = (char *)result;
9075 LOGD("variant info %d:%s", *num, *var_info);
9081 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9083 int ret = MM_ERROR_NONE;
9084 mmplayer_t *player = (mmplayer_t *)hplayer;
9087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9089 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9091 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9092 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9093 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9095 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9096 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9097 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9098 "max-bitrate", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9100 /* FIXME: seek to current position for applying new variant limitation */
9109 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9111 int ret = MM_ERROR_NONE;
9112 mmplayer_t *player = (mmplayer_t *)hplayer;
9115 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9116 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9118 *bandwidth = player->adaptive_info.limit.bandwidth;
9119 *width = player->adaptive_info.limit.width;
9120 *height = player->adaptive_info.limit.height;
9122 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9129 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9131 int ret = MM_ERROR_NONE;
9132 mmplayer_t *player = (mmplayer_t *)hplayer;
9135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9136 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9137 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9139 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9141 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9142 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9143 else /* live case */
9144 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9146 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9153 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9155 #define IDX_FIRST_SW_CODEC 0
9156 mmplayer_t *player = (mmplayer_t *)hplayer;
9157 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9158 const char *attr_name = NULL;
9159 const char *default_type = NULL;
9160 const char *element_hw = NULL;
9161 const char *element_sw = NULL;
9164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9166 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9168 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9169 switch (stream_type) {
9170 case MM_PLAYER_STREAM_TYPE_AUDIO:
9171 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9172 default_type = player->ini.audiocodec_default_type;
9173 element_hw = player->ini.audiocodec_element_hw;
9174 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9176 case MM_PLAYER_STREAM_TYPE_VIDEO:
9177 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9178 default_type = player->ini.videocodec_default_type;
9179 element_hw = player->ini.videocodec_element_hw;
9180 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9183 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9184 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9188 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9190 if (!strcmp(default_type, "sw"))
9191 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9193 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9195 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9196 codec_type = default_codec_type;
9198 /* to support codec selection, codec info have to be added in ini file.
9199 in case of hw codec is selected, filter elements should be applied
9200 depending on the hw capabilities. */
9201 if (codec_type != default_codec_type) {
9202 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9203 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9204 LOGE("There is no codec for type %d", codec_type);
9205 return MM_ERROR_PLAYER_NO_OP;
9208 LOGD("sorting is required");
9209 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9210 player->need_audio_dec_sorting = TRUE;
9212 player->need_video_dec_sorting = TRUE;
9215 LOGD("update %s codec_type to %d", attr_name, codec_type);
9216 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9219 return MM_ERROR_NONE;
9223 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9225 mmplayer_t *player = (mmplayer_t *)hplayer;
9226 GstElement *rg_vol_element = NULL;
9230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9232 player->sound.rg_enable = enabled;
9234 /* just hold rgvolume enable value if pipeline is not ready */
9235 if (!player->pipeline || !player->pipeline->audiobin) {
9236 LOGD("pipeline is not ready. holding rgvolume enable value");
9237 return MM_ERROR_NONE;
9240 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9242 if (!rg_vol_element) {
9243 LOGD("rgvolume element is not created");
9244 return MM_ERROR_PLAYER_INTERNAL;
9248 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9250 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9254 return MM_ERROR_NONE;
9258 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9260 mmplayer_t *player = (mmplayer_t *)hplayer;
9261 GstElement *rg_vol_element = NULL;
9262 gboolean enable = FALSE;
9266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9267 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9269 /* just hold enable_rg value if pipeline is not ready */
9270 if (!player->pipeline || !player->pipeline->audiobin) {
9271 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9272 *enabled = player->sound.rg_enable;
9273 return MM_ERROR_NONE;
9276 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9278 if (!rg_vol_element) {
9279 LOGD("rgvolume element is not created");
9280 return MM_ERROR_PLAYER_INTERNAL;
9283 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9284 *enabled = (bool)enable;
9288 return MM_ERROR_NONE;
9292 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9294 mmplayer_t *player = (mmplayer_t *)hplayer;
9295 MMHandleType attrs = 0;
9297 int ret = MM_ERROR_NONE;
9301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9303 attrs = MMPLAYER_GET_ATTRS(player);
9304 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9306 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9308 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9309 return MM_ERROR_PLAYER_INTERNAL;
9312 player->video_roi.scale_x = scale_x;
9313 player->video_roi.scale_y = scale_y;
9314 player->video_roi.scale_width = scale_width;
9315 player->video_roi.scale_height = scale_height;
9317 /* check video sinkbin is created */
9318 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9319 return MM_ERROR_NONE;
9321 if (!gst_video_overlay_set_video_roi_area(
9322 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9323 scale_x, scale_y, scale_width, scale_height))
9324 ret = MM_ERROR_PLAYER_INTERNAL;
9326 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9327 scale_x, scale_y, scale_width, scale_height);
9335 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9337 mmplayer_t *player = (mmplayer_t *)hplayer;
9338 int ret = MM_ERROR_NONE;
9342 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9343 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9345 *scale_x = player->video_roi.scale_x;
9346 *scale_y = player->video_roi.scale_y;
9347 *scale_width = player->video_roi.scale_width;
9348 *scale_height = player->video_roi.scale_height;
9350 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9351 *scale_x, *scale_y, *scale_width, *scale_height);
9357 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9359 mmplayer_t *player = (mmplayer_t *)hplayer;
9363 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9365 player->client_pid = pid;
9367 LOGD("client pid[%d] %p", pid, player);
9371 return MM_ERROR_NONE;
9375 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9377 mmplayer_t *player = (mmplayer_t *)hplayer;
9378 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9379 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9384 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9387 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9389 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9391 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9392 return MM_ERROR_NONE;
9394 /* in case of audio codec default type is HW */
9396 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9397 if (player->ini.support_audio_effect)
9398 return MM_ERROR_NONE;
9399 elem_id = MMPLAYER_A_FILTER;
9401 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9402 if (player->ini.support_replaygain_control)
9403 return MM_ERROR_NONE;
9404 elem_id = MMPLAYER_A_RGVOL;
9406 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9407 if (player->ini.support_pitch_control)
9408 return MM_ERROR_NONE;
9409 elem_id = MMPLAYER_A_PITCH;
9411 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9412 if (player->ini.support_audio_effect)
9413 return MM_ERROR_NONE;
9415 /* default case handling is not required */
9418 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9419 LOGW("audio control option [%d] is not available", opt);
9422 /* setting pcm exporting option is allowed before READY state */
9423 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9424 return MM_ERROR_PLAYER_INVALID_STATE;
9426 /* check whether the audio filter exist or not after READY state,
9427 because the sw codec could be added during auto-plugging in some cases */
9428 if (!player->pipeline ||
9429 !player->pipeline->audiobin ||
9430 !player->pipeline->audiobin[elem_id].gst) {
9431 LOGW("there is no audio elem [%d]", elem_id);
9436 LOGD("audio control opt %d, available %d", opt, *available);
9440 return MM_ERROR_NONE;
9444 __mmplayer_update_duration_value(mmplayer_t *player)
9446 gboolean ret = FALSE;
9447 gint64 dur_nsec = 0;
9448 LOGD("try to update duration");
9450 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9451 player->duration = dur_nsec;
9452 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9456 if (player->duration < 0) {
9457 LOGW("duration is Non-Initialized !!!");
9458 player->duration = 0;
9461 /* update streaming service type */
9462 player->streaming_type = _mmplayer_get_stream_service_type(player);
9464 /* check duration is OK */
9465 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9466 /* FIXIT : find another way to get duration here. */
9467 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9473 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9475 /* update audio params
9476 NOTE : We need original audio params and it can be only obtained from src pad of audio
9477 decoder. Below code only valid when we are not using 'resampler' just before
9478 'audioconverter'. */
9479 GstCaps *caps_a = NULL;
9481 gint samplerate = 0, channels = 0;
9482 GstStructure *p = NULL;
9483 GstElement *aconv = NULL;
9485 LOGD("try to update audio attrs");
9487 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9489 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9490 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9491 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9492 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9494 LOGE("there is no audio converter");
9498 pad = gst_element_get_static_pad(aconv, "sink");
9501 LOGW("failed to get pad from audio converter");
9505 caps_a = gst_pad_get_current_caps(pad);
9507 LOGW("not ready to get audio caps");
9508 gst_object_unref(pad);
9512 p = gst_caps_get_structure(caps_a, 0);
9513 gst_structure_get_int(p, "rate", &samplerate);
9514 gst_structure_get_int(p, "channels", &channels);
9516 mm_player_set_attribute((MMHandleType)player, NULL,
9517 "content_audio_samplerate", samplerate,
9518 "content_audio_channels", channels, NULL);
9520 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9522 gst_caps_unref(caps_a);
9523 gst_object_unref(pad);
9529 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9531 LOGD("try to update video attrs");
9533 GstCaps *caps_v = NULL;
9537 GstStructure *p = NULL;
9539 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9540 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9542 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9544 LOGD("no videosink sink pad");
9548 caps_v = gst_pad_get_current_caps(pad);
9549 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9550 if (!caps_v && player->v_stream_caps) {
9551 caps_v = player->v_stream_caps;
9552 gst_caps_ref(caps_v);
9556 LOGD("no negotiated caps from videosink");
9557 gst_object_unref(pad);
9561 p = gst_caps_get_structure(caps_v, 0);
9562 gst_structure_get_int(p, "width", &width);
9563 gst_structure_get_int(p, "height", &height);
9565 mm_player_set_attribute((MMHandleType)player, NULL,
9566 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9568 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9570 SECURE_LOGD("width : %d height : %d", width, height);
9572 gst_caps_unref(caps_v);
9573 gst_object_unref(pad);
9576 mm_player_set_attribute((MMHandleType)player, NULL,
9577 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9578 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9585 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9587 gboolean ret = FALSE;
9588 guint64 data_size = 0;
9592 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9593 if (!player->duration)
9596 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9597 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9598 if (stat(path, &sb) == 0)
9599 data_size = (guint64)sb.st_size;
9601 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9602 data_size = player->http_content_size;
9605 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9608 guint64 bitrate = 0;
9609 guint64 msec_dur = 0;
9611 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9613 bitrate = data_size * 8 * 1000 / msec_dur;
9614 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9615 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9616 mm_player_set_attribute((MMHandleType)player, NULL,
9617 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9620 LOGD("player duration is less than 0");
9624 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9625 if (player->total_bitrate) {
9626 mm_player_set_attribute((MMHandleType)player, NULL,
9627 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9636 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9638 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9639 data->uri_type = uri_type;
9643 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9645 int ret = MM_ERROR_PLAYER_INVALID_URI;
9647 char *buffer = NULL;
9648 char *seperator = strchr(path, ',');
9649 char ext[100] = {0,}, size[100] = {0,};
9652 if ((buffer = strstr(path, "ext="))) {
9653 buffer += strlen("ext=");
9655 if (strlen(buffer)) {
9656 strncpy(ext, buffer, 99);
9658 if ((seperator = strchr(ext, ','))
9659 || (seperator = strchr(ext, ' '))
9660 || (seperator = strchr(ext, '\0'))) {
9661 seperator[0] = '\0';
9666 if ((buffer = strstr(path, "size="))) {
9667 buffer += strlen("size=");
9669 if (strlen(buffer) > 0) {
9670 strncpy(size, buffer, 99);
9672 if ((seperator = strchr(size, ','))
9673 || (seperator = strchr(size, ' '))
9674 || (seperator = strchr(size, '\0'))) {
9675 seperator[0] = '\0';
9678 mem_size = atoi(size);
9683 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9685 if (mem_size && param) {
9686 if (data->input_mem.buf)
9687 free(data->input_mem.buf);
9688 data->input_mem.buf = malloc(mem_size);
9690 if (data->input_mem.buf) {
9691 memcpy(data->input_mem.buf, param, mem_size);
9692 data->input_mem.len = mem_size;
9693 ret = MM_ERROR_NONE;
9695 LOGE("failed to alloc mem %d", mem_size);
9696 ret = MM_ERROR_PLAYER_INTERNAL;
9699 data->input_mem.offset = 0;
9700 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9707 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9709 gchar *location = NULL;
9712 int ret = MM_ERROR_NONE;
9714 if ((path = strstr(uri, "file://"))) {
9715 location = g_filename_from_uri(uri, NULL, &err);
9716 if (!location || (err != NULL)) {
9717 LOGE("Invalid URI '%s' for filesrc: %s", path,
9718 (err != NULL) ? err->message : "unknown error");
9722 MMPLAYER_FREEIF(location);
9724 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9725 return MM_ERROR_PLAYER_INVALID_URI;
9727 LOGD("path from uri: %s", location);
9730 path = (location != NULL) ? (location) : ((char *)uri);
9733 ret = _mmplayer_exist_file_path(path);
9735 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9736 if (ret == MM_ERROR_NONE) {
9737 if (_mmplayer_is_sdp_file(path)) {
9738 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9739 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9740 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9742 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9743 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9745 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9746 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9748 LOGE("invalid uri, could not play..");
9749 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9752 MMPLAYER_FREEIF(location);
9757 static mmplayer_video_decoded_data_info_t *
9758 __mmplayer_create_stream_from_pad(GstPad *pad)
9760 GstCaps *caps = NULL;
9761 GstStructure *structure = NULL;
9762 unsigned int fourcc = 0;
9763 const gchar *string_format = NULL;
9764 mmplayer_video_decoded_data_info_t *stream = NULL;
9766 MMPixelFormatType format;
9769 caps = gst_pad_get_current_caps(pad);
9771 LOGE("Caps is NULL.");
9776 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9778 structure = gst_caps_get_structure(caps, 0);
9779 gst_structure_get_int(structure, "width", &width);
9780 gst_structure_get_int(structure, "height", &height);
9781 string_format = gst_structure_get_string(structure, "format");
9784 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9785 format = _mmplayer_get_pixtype(fourcc);
9786 gst_video_info_from_caps(&info, caps);
9787 gst_caps_unref(caps);
9790 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9791 LOGE("Wrong condition!!");
9795 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9797 LOGE("failed to alloc mem for video data");
9801 stream->width = width;
9802 stream->height = height;
9803 stream->format = format;
9804 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9810 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9812 unsigned int pitch = 0;
9813 unsigned int size = 0;
9815 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9818 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9819 bo = gst_tizen_memory_get_bos(mem, index);
9821 stream->bo[index] = tbm_bo_ref(bo);
9823 LOGE("failed to get bo for index %d", index);
9826 for (index = 0; index < stream->plane_num; index++) {
9827 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9828 stream->stride[index] = pitch;
9830 stream->elevation[index] = size / pitch;
9832 stream->elevation[index] = stream->height;
9837 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9839 if (stream->format == MM_PIXEL_FORMAT_I420) {
9840 int ret = TBM_SURFACE_ERROR_NONE;
9841 tbm_surface_h surface;
9842 tbm_surface_info_s info;
9844 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9846 ret = tbm_surface_get_info(surface, &info);
9847 if (ret != TBM_SURFACE_ERROR_NONE) {
9848 tbm_surface_destroy(surface);
9852 tbm_surface_destroy(surface);
9853 stream->stride[0] = info.planes[0].stride;
9854 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9855 stream->stride[1] = info.planes[1].stride;
9856 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9857 stream->stride[2] = info.planes[2].stride;
9858 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9859 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9860 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9861 stream->stride[0] = stream->width * 4;
9862 stream->elevation[0] = stream->height;
9863 stream->bo_size = stream->stride[0] * stream->height;
9865 LOGE("Not support format %d", stream->format);
9873 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9875 tbm_bo_handle thandle;
9877 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9878 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9879 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9883 unsigned char *src = NULL;
9884 unsigned char *dest = NULL;
9885 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9887 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9889 LOGE("fail to gst_memory_map");
9893 if (!mapinfo.data) {
9894 LOGE("data pointer is wrong");
9898 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9899 if (!stream->bo[0]) {
9900 LOGE("Fail to tbm_bo_alloc!!");
9904 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9906 LOGE("thandle pointer is wrong");
9910 if (stream->format == MM_PIXEL_FORMAT_I420) {
9911 src_stride[0] = GST_ROUND_UP_4(stream->width);
9912 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9913 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9914 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9917 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9918 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9920 for (i = 0; i < 3; i++) {
9921 src = mapinfo.data + src_offset[i];
9922 dest = thandle.ptr + dest_offset[i];
9927 for (j = 0; j < stream->height >> k; j++) {
9928 memcpy(dest, src, stream->width>>k);
9929 src += src_stride[i];
9930 dest += stream->stride[i];
9933 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9934 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9936 LOGE("Not support format %d", stream->format);
9940 tbm_bo_unmap(stream->bo[0]);
9941 gst_memory_unmap(mem, &mapinfo);
9947 tbm_bo_unmap(stream->bo[0]);
9950 gst_memory_unmap(mem, &mapinfo);
9956 __mmplayer_set_pause_state(mmplayer_t *player)
9958 if (player->sent_bos)
9961 /* rtsp case, get content attrs by GstMessage */
9962 if (MMPLAYER_IS_RTSP_STREAMING(player))
9965 /* it's first time to update all content attrs. */
9966 _mmplayer_update_content_attrs(player, ATTR_ALL);
9970 __mmplayer_set_playing_state(mmplayer_t *player)
9972 gchar *audio_codec = NULL;
9974 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9975 /* initialize because auto resume is done well. */
9976 player->resumed_by_rewind = FALSE;
9977 player->playback_rate = 1.0;
9980 if (player->sent_bos)
9983 /* try to get content metadata */
9985 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9986 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9987 * legacy mmfw-player api
9989 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9991 if ((player->cmd == MMPLAYER_COMMAND_START)
9992 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9993 __mmplayer_handle_missed_plugin(player);
9996 /* check audio codec field is set or not
9997 * we can get it from typefinder or codec's caps.
9999 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
10001 /* The codec format can't be sent for audio only case like amr, mid etc.
10002 * Because, parser don't make related TAG.
10003 * So, if it's not set yet, fill it with found data.
10005 if (!audio_codec) {
10006 if (g_strrstr(player->type_caps_str, "audio/midi"))
10007 audio_codec = "MIDI";
10008 else if (g_strrstr(player->type_caps_str, "audio/x-amr"))
10009 audio_codec = "AMR";
10010 else if (g_strrstr(player->type_caps_str, "audio/mpeg")
10011 && !g_strrstr(player->type_caps_str, "mpegversion=(int)1"))
10012 audio_codec = "AAC";
10014 audio_codec = "unknown";
10016 if (mm_player_set_attribute((MMHandleType)player, NULL,
10017 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
10018 LOGE("failed to set attribute");
10020 LOGD("set audio codec type with caps");