4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 #define MQ_UNLINKED_CACHE_TIME (500 * GST_MSECOND)
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
146 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
147 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static void __mmplayer_release_misc(mmplayer_t *player);
152 static void __mmplayer_release_misc_post(mmplayer_t *player);
153 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
154 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
157 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
159 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
160 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
161 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
162 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
164 static gpointer __mmplayer_gapless_play_thread(gpointer data);
165 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
166 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_release_dump_list(GList *dump_list);
168 static int __mmplayer_gst_realize(mmplayer_t *player);
169 static int __mmplayer_gst_unrealize(mmplayer_t *player);
170 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
171 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
174 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
175 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
176 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
177 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
178 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
179 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
180 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
181 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
182 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
183 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
184 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
185 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
187 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
189 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
190 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
191 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
193 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
194 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
195 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
196 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
198 static void __mmplayer_set_pause_state(mmplayer_t *player);
199 static void __mmplayer_set_playing_state(mmplayer_t *player);
200 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
201 /*===========================================================================================
203 | FUNCTION DEFINITIONS |
205 ========================================================================================== */
207 /* This function should be called after the pipeline goes PAUSED or higher
210 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
212 static gboolean has_duration = FALSE;
213 static gboolean has_video_attrs = FALSE;
214 static gboolean has_audio_attrs = FALSE;
215 static gboolean has_bitrate = FALSE;
216 gboolean missing_only = FALSE;
217 gboolean all = FALSE;
218 MMHandleType attrs = 0;
222 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
224 /* check player state here */
225 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
226 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
227 /* give warning now only */
228 LOGW("be careful. content attributes may not available in this state ");
231 /* get content attribute first */
232 attrs = MMPLAYER_GET_ATTRS(player);
234 LOGE("cannot get content attribute");
238 /* get update flag */
240 if (flag & ATTR_MISSING_ONLY) {
242 LOGD("updating missed attr only");
245 if (flag & ATTR_ALL) {
247 has_duration = FALSE;
248 has_video_attrs = FALSE;
249 has_audio_attrs = FALSE;
252 LOGD("updating all attrs");
255 if (missing_only && all) {
256 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
257 missing_only = FALSE;
260 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
261 has_duration = __mmplayer_update_duration_value(player);
263 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
264 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
266 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
267 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
269 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
270 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
278 _mmplayer_get_stream_service_type(mmplayer_t *player)
280 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
284 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
286 player->pipeline->mainbin &&
287 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
288 STREAMING_SERVICE_NONE);
290 /* streaming service type if streaming */
291 if (!MMPLAYER_IS_STREAMING(player))
292 return STREAMING_SERVICE_NONE;
294 streaming_type = (player->duration == 0) ?
295 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
297 switch (streaming_type) {
298 case STREAMING_SERVICE_LIVE:
299 LOGD("it's live streaming");
301 case STREAMING_SERVICE_VOD:
302 LOGD("it's vod streaming");
305 LOGE("should not get here");
311 return streaming_type;
314 /* this function sets the player state and also report
315 * it to application by calling callback function
318 _mmplayer_set_state(mmplayer_t *player, int state)
320 MMMessageParamType msg = {0, };
322 MMPLAYER_RETURN_IF_FAIL(player);
324 if (MMPLAYER_CURRENT_STATE(player) == state) {
325 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
326 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
330 /* update player states */
331 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
332 MMPLAYER_CURRENT_STATE(player) = state;
334 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
335 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
338 MMPLAYER_PRINT_STATE(player);
340 switch (MMPLAYER_CURRENT_STATE(player)) {
341 case MM_PLAYER_STATE_NULL:
342 case MM_PLAYER_STATE_READY:
344 case MM_PLAYER_STATE_PAUSED:
345 __mmplayer_set_pause_state(player);
347 case MM_PLAYER_STATE_PLAYING:
348 __mmplayer_set_playing_state(player);
350 case MM_PLAYER_STATE_NONE:
352 LOGW("invalid target state, there is nothing to do.");
357 /* post message to application */
358 if (MMPLAYER_TARGET_STATE(player) == state) {
359 /* fill the message with state of player */
360 msg.union_type = MM_MSG_UNION_STATE;
361 msg.state.previous = MMPLAYER_PREV_STATE(player);
362 msg.state.current = MMPLAYER_CURRENT_STATE(player);
364 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
366 /* state changed by resource callback */
367 if (player->interrupted_by_resource)
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
369 else /* state changed by usecase */
370 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
373 LOGD("intermediate state, do nothing.");
374 MMPLAYER_PRINT_STATE(player);
378 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
379 && !player->sent_bos) {
380 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
381 player->sent_bos = TRUE;
388 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
390 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
391 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
395 LOGD("incoming command : %d ", command);
397 current_state = MMPLAYER_CURRENT_STATE(player);
398 pending_state = MMPLAYER_PENDING_STATE(player);
400 MMPLAYER_PRINT_STATE(player);
403 case MMPLAYER_COMMAND_CREATE:
405 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
407 if (current_state == MM_PLAYER_STATE_NULL ||
408 current_state == MM_PLAYER_STATE_READY ||
409 current_state == MM_PLAYER_STATE_PAUSED ||
410 current_state == MM_PLAYER_STATE_PLAYING)
415 case MMPLAYER_COMMAND_DESTROY:
417 /* destroy can called anytime */
419 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
423 case MMPLAYER_COMMAND_REALIZE:
425 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
427 if (pending_state != MM_PLAYER_STATE_NONE) {
430 /* need ready state to realize */
431 if (current_state == MM_PLAYER_STATE_READY)
434 if (current_state != MM_PLAYER_STATE_NULL)
440 case MMPLAYER_COMMAND_UNREALIZE:
442 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
444 if (current_state == MM_PLAYER_STATE_NULL)
449 case MMPLAYER_COMMAND_START:
451 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
453 if (pending_state == MM_PLAYER_STATE_NONE) {
454 if (current_state == MM_PLAYER_STATE_PLAYING)
456 else if (current_state != MM_PLAYER_STATE_READY &&
457 current_state != MM_PLAYER_STATE_PAUSED)
459 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
461 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
462 LOGD("player is going to paused state, just change the pending state as playing");
469 case MMPLAYER_COMMAND_STOP:
471 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
473 if (current_state == MM_PLAYER_STATE_READY)
476 /* need playing/paused state to stop */
477 if (current_state != MM_PLAYER_STATE_PLAYING &&
478 current_state != MM_PLAYER_STATE_PAUSED)
483 case MMPLAYER_COMMAND_PAUSE:
485 if (MMPLAYER_IS_LIVE_STREAMING(player))
488 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
489 goto NOT_COMPLETED_SEEK;
491 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
493 if (pending_state == MM_PLAYER_STATE_NONE) {
494 if (current_state == MM_PLAYER_STATE_PAUSED)
496 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
498 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
501 if (current_state == MM_PLAYER_STATE_PAUSED)
502 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
509 case MMPLAYER_COMMAND_RESUME:
511 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
512 goto NOT_COMPLETED_SEEK;
514 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
516 if (pending_state == MM_PLAYER_STATE_NONE) {
517 if (current_state == MM_PLAYER_STATE_PLAYING)
519 else if (current_state != MM_PLAYER_STATE_PAUSED)
521 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
523 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
524 LOGD("player is going to paused state, just change the pending state as playing");
534 player->cmd = command;
536 return MM_ERROR_NONE;
539 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
540 MMPLAYER_STATE_GET_NAME(current_state), command);
541 return MM_ERROR_PLAYER_INVALID_STATE;
544 LOGW("not completed seek");
545 return MM_ERROR_PLAYER_DOING_SEEK;
548 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
549 return MM_ERROR_PLAYER_NO_OP;
552 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
553 return MM_ERROR_PLAYER_NO_OP;
556 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
558 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
559 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
562 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
563 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
565 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
566 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
568 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
569 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
572 LOGE("invalid mmplayer resource type %d", type);
573 return MM_ERROR_PLAYER_INTERNAL;
576 if (player->hw_resource[type] != NULL) {
577 LOGD("[%d type] resource was already acquired", type);
578 return MM_ERROR_NONE;
581 LOGD("mark for acquire [%d type] resource", type);
582 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
583 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
584 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
585 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
586 return MM_ERROR_PLAYER_INTERNAL;
589 LOGD("commit [%d type] resource", type);
590 rm_ret = mm_resource_manager_commit(player->resource_manager);
591 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
592 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
593 return MM_ERROR_PLAYER_INTERNAL;
597 return MM_ERROR_NONE;
600 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
602 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
604 MMPLAYER_RETURN_IF_FAIL(player);
605 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
607 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
608 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
609 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
613 rm_ret = mm_resource_manager_commit(player->resource_manager);
614 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
615 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
618 /* de-initialize resource manager */
619 rm_ret = mm_resource_manager_destroy(player->resource_manager);
620 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
621 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
625 player->resource_manager = NULL;
627 LOGD("resource manager is destroyed");
630 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
632 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
636 if (player->hw_resource[type] == NULL) {
637 LOGD("there is no acquired [%d type] resource", type);
638 return MM_ERROR_NONE;
641 LOGD("mark for release [%d type] resource", type);
642 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
643 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
644 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
645 return MM_ERROR_PLAYER_INTERNAL;
648 player->hw_resource[type] = NULL;
650 LOGD("commit [%d type] resource", type);
651 rm_ret = mm_resource_manager_commit(player->resource_manager);
652 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
653 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
654 return MM_ERROR_PLAYER_INTERNAL;
658 return MM_ERROR_NONE;
662 __mmplayer_initialize_gapless_play(mmplayer_t *player)
668 player->smooth_streaming = FALSE;
669 player->videodec_linked = 0;
670 player->audiodec_linked = 0;
671 player->textsink_linked = 0;
672 player->is_external_subtitle_present = FALSE;
673 player->is_external_subtitle_added_now = FALSE;
674 player->not_supported_codec = MISSING_PLUGIN_NONE;
675 player->can_support_codec = FOUND_PLUGIN_NONE;
676 player->pending_seek.is_pending = false;
677 player->pending_seek.pos = 0;
678 player->msg_posted = FALSE;
679 player->has_many_types = FALSE;
680 player->no_more_pad = FALSE;
681 player->not_found_demuxer = 0;
682 player->seek_state = MMPLAYER_SEEK_NONE;
683 player->is_subtitle_force_drop = FALSE;
684 player->play_subtitle = FALSE;
685 player->adjust_subtitle_pos = 0;
687 player->total_bitrate = 0;
688 player->total_maximum_bitrate = 0;
690 _mmplayer_track_initialize(player);
691 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
693 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
694 player->bitrate[i] = 0;
695 player->maximum_bitrate[i] = 0;
698 if (player->v_stream_caps) {
699 gst_caps_unref(player->v_stream_caps);
700 player->v_stream_caps = NULL;
703 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
705 /* clean found audio decoders */
706 if (player->audio_decoders) {
707 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
708 player->audio_decoders = NULL;
711 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
716 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
718 LOGI("set pipeline reconfigure state %d", state);
719 MMPLAYER_RECONFIGURE_LOCK(player);
720 player->gapless.reconfigure = state;
721 if (!state) /* wake up the waiting job */
722 MMPLAYER_RECONFIGURE_SIGNAL(player);
723 MMPLAYER_RECONFIGURE_UNLOCK(player);
727 __mmplayer_gapless_play_thread(gpointer data)
729 mmplayer_t *player = (mmplayer_t *)data;
730 mmplayer_gst_element_t *mainbin = NULL;
732 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
734 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
735 while (!player->gapless_play_thread_exit) {
736 LOGD("gapless play thread started. waiting for signal.");
737 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
739 LOGD("reconfigure pipeline for gapless play.");
741 if (player->gapless_play_thread_exit) {
742 _mmplayer_set_reconfigure_state(player, FALSE);
743 LOGD("exiting gapless play thread");
747 mainbin = player->pipeline->mainbin;
749 if (MMPLAYER_USE_DECODEBIN(player)) {
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
756 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
757 mainbin[MMPLAYER_M_SRC].gst = NULL;
760 /* Initialize Player values */
761 __mmplayer_initialize_gapless_play(player);
763 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
765 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
771 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
773 GSource *source = NULL;
777 source = g_main_context_find_source_by_id(context, source_id);
778 if (source != NULL) {
779 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
780 g_source_destroy(source);
787 _mmplayer_watcher_removed_notify(gpointer data)
789 mmplayer_t *player = (mmplayer_t *)data;
790 MMPLAYER_RETURN_IF_FAIL(player);
792 MMPLAYER_BUS_WATCHER_LOCK(player);
793 player->bus_watcher = 0;
794 MMPLAYER_BUS_WATCHER_SIGNAL(player);
795 MMPLAYER_BUS_WATCHER_UNLOCK(player);
799 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
801 mmplayer_t *player = (mmplayer_t *)hplayer;
804 MMPLAYER_RETURN_IF_FAIL(player);
806 /* disconnecting bus watch */
807 if (player->bus_watcher > 0) {
808 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
809 MMPLAYER_BUS_WATCHER_LOCK(player);
810 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
811 while (player->bus_watcher > 0) {
812 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
813 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
814 player->bus_watcher);
818 MMPLAYER_BUS_WATCHER_UNLOCK(player);
819 g_mutex_clear(&player->bus_watcher_mutex);
820 g_cond_clear(&player->bus_watcher_cond);
827 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
829 mmplayer_t *player = (mmplayer_t *)hplayer;
830 GstMessage *msg = NULL;
831 GQueue *queue = NULL;
834 MMPLAYER_RETURN_IF_FAIL(player);
836 /* destroy the gst bus msg thread */
837 if (player->bus_msg_thread) {
838 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
839 player->bus_msg_thread_exit = TRUE;
840 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
841 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
843 LOGD("gst bus msg thread exit.");
844 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
845 player->bus_msg_thread = NULL;
847 g_mutex_clear(&player->bus_msg_thread_mutex);
848 g_cond_clear(&player->bus_msg_thread_cond);
851 g_mutex_lock(&player->bus_msg_q_lock);
852 queue = player->bus_msg_q;
853 while (!g_queue_is_empty(queue)) {
854 msg = (GstMessage *)g_queue_pop_head(queue);
859 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
860 gst_message_unref(msg);
862 g_mutex_unlock(&player->bus_msg_q_lock);
868 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
870 GstElement *parent = NULL;
872 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
873 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
876 MMPLAYER_FSINK_LOCK(player);
878 /* get parent of fakesink */
879 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
881 LOGD("fakesink already removed");
885 gst_element_set_locked_state(fakesink->gst, TRUE);
887 /* setting the state to NULL never returns async
888 * so no need to wait for completion of state transition
890 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
891 LOGE("fakesink state change failure!");
892 /* FIXIT : should I return here? or try to proceed to next? */
895 /* remove fakesink from it's parent */
896 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
897 LOGE("failed to remove fakesink");
899 gst_object_unref(parent);
904 gst_object_unref(parent);
906 LOGD("state-holder removed");
908 gst_element_set_locked_state(fakesink->gst, FALSE);
910 MMPLAYER_FSINK_UNLOCK(player);
915 gst_element_set_locked_state(fakesink->gst, FALSE);
917 MMPLAYER_FSINK_UNLOCK(player);
921 static GstPadProbeReturn
922 __mmplayer_gst_combiner_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
925 return GST_PAD_PROBE_OK;
929 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
931 gint64 stop_running_time = 0;
932 gint64 position_running_time = 0;
936 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
937 if ((player->gapless.update_segment[idx] == TRUE) ||
938 !(player->track[idx].event_probe_id)) {
940 LOGW("[%d] skip", idx);
945 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
947 gst_segment_to_running_time(&player->gapless.segment[idx],
948 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
949 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
951 gst_segment_to_running_time(&player->gapless.segment[idx],
952 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
954 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
956 gst_segment_to_running_time(&player->gapless.segment[idx],
957 GST_FORMAT_TIME, player->duration);
960 position_running_time =
961 gst_segment_to_running_time(&player->gapless.segment[idx],
962 GST_FORMAT_TIME, player->gapless.segment[idx].position);
964 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
965 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
967 GST_TIME_ARGS(stop_running_time),
968 GST_TIME_ARGS(position_running_time),
969 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
970 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
972 position_running_time = MAX(position_running_time, stop_running_time);
973 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
974 GST_FORMAT_TIME, player->gapless.segment[idx].start);
975 position_running_time = MAX(0, position_running_time);
976 position = MAX(position, position_running_time);
980 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
981 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
982 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
984 player->gapless.start_time[stream_type] += position;
990 static GstPadProbeReturn
991 __mmplayer_gst_combiner_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
993 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
994 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
995 mmplayer_t *player = (mmplayer_t *)data;
996 GstCaps *caps = NULL;
997 GstStructure *str = NULL;
998 const gchar *name = NULL;
999 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1000 gboolean caps_ret = TRUE;
1002 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1005 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1006 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1009 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1011 GstStream *stream = NULL;
1013 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START)
1016 gst_event_parse_stream (event, &stream);
1017 if (stream == NULL) {
1018 LOGW ("Got a STREAM_START event without a GstStream");
1022 name = gst_stream_type_get_name(gst_stream_get_stream_type(stream));
1023 gst_object_unref (stream);
1029 if (strstr(name, "audio")) {
1030 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1031 } else if (strstr(name, "video")) {
1032 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1034 /* text track is not supportable */
1035 LOGE("invalid name %s", name);
1039 switch (GST_EVENT_TYPE(event)) {
1042 /* in case of gapless, drop eos event not to send it to sink */
1043 if (player->gapless.reconfigure && !player->msg_posted) {
1044 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1045 ret = GST_PAD_PROBE_DROP;
1049 case GST_EVENT_STREAM_START:
1051 __mmplayer_gst_selector_update_start_time(player, stream_type);
1054 case GST_EVENT_FLUSH_STOP:
1056 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1057 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1058 player->gapless.start_time[stream_type] = 0;
1061 case GST_EVENT_SEGMENT:
1066 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1067 gst_event_copy_segment(event, &segment);
1069 if (segment.format != GST_FORMAT_TIME)
1072 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1073 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1074 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1075 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1076 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1077 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1079 /* keep the all the segment ev to cover the seeking */
1080 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1081 player->gapless.update_segment[stream_type] = TRUE;
1083 if (!player->gapless.running)
1086 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1088 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1090 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1091 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1092 gst_event_unref(event);
1093 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1099 gdouble proportion = 0.0;
1100 GstClockTimeDiff diff = 0;
1101 GstClockTime timestamp = 0;
1102 gint64 running_time_diff = -1;
1103 GstQOSType type = 0;
1104 GstEvent *tmpev = NULL;
1106 running_time_diff = player->gapless.segment[stream_type].base;
1108 if (running_time_diff <= 0) /* don't need to adjust */
1111 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1112 gst_event_unref(event);
1114 if (timestamp < running_time_diff) {
1115 LOGW("QOS event from previous group");
1116 ret = GST_PAD_PROBE_DROP;
1121 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1122 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1123 stream_type, GST_TIME_ARGS(timestamp),
1124 GST_TIME_ARGS(running_time_diff),
1125 GST_TIME_ARGS(timestamp - running_time_diff));
1128 timestamp -= running_time_diff;
1130 /* That case is invalid for QoS events */
1131 if (diff < 0 && -diff > timestamp) {
1132 LOGW("QOS event from previous group");
1133 ret = GST_PAD_PROBE_DROP;
1137 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1138 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1148 gst_caps_unref(caps);
1152 /* create fakesink for audio or video path without audiobin or videobin */
1154 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1156 GstElement *pipeline = NULL;
1157 GstElement *fakesink = NULL;
1158 GstPad *sinkpad = NULL;
1161 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1163 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1166 fakesink = gst_element_factory_make("fakesink", NULL);
1167 if (fakesink == NULL) {
1168 LOGE("failed to create fakesink");
1172 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1173 LOGE("failed to add fakesink to pipeline");
1178 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1180 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1182 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1183 LOGE("failed to link fakesink");
1187 if (strstr(name, "video")) {
1188 if (player->v_stream_caps) {
1189 gst_caps_unref(player->v_stream_caps);
1190 player->v_stream_caps = NULL;
1192 if (player->ini.set_dump_element_flag)
1193 __mmplayer_add_dump_buffer_probe(player, fakesink);
1196 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1197 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1199 /* store it as it's sink element */
1200 __mmplayer_add_sink(player, fakesink, FALSE);
1203 gst_object_unref(GST_OBJECT(sinkpad));
1211 gst_object_unref(GST_OBJECT(sinkpad));
1214 gst_element_set_state(fakesink, GST_STATE_NULL);
1216 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1217 gst_object_unref(GST_OBJECT(fakesink));
1224 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1226 GstElement *pipeline = NULL;
1227 g_autoptr(GstElement) concat = NULL;
1228 g_autoptr(GstPad) srcpad = NULL;
1231 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1233 concat = gst_element_factory_make("concat", NULL);
1235 LOGE("failed to create concat");
1239 srcpad = gst_element_get_static_pad(concat, "src");
1241 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1242 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1243 __mmplayer_gst_combiner_blocked, NULL, NULL);
1244 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1245 __mmplayer_gst_combiner_event_probe, player, NULL);
1248 gst_element_set_state(concat, GST_STATE_PAUSED);
1250 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1251 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1252 LOGE("failed to add concat to pipeline");
1253 gst_element_set_state(concat, GST_STATE_NULL);
1257 LOGD("Create concat [%d] element", elem_idx);
1259 player->pipeline->mainbin[elem_idx].id = elem_idx;
1260 player->pipeline->mainbin[elem_idx].gst = concat;
1263 return g_steal_pointer(&concat);
1267 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1269 GstElement *pipeline = NULL;
1270 GstElement *selector = NULL;
1271 GstPad *srcpad = NULL;
1274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1276 selector = gst_element_factory_make("input-selector", NULL);
1278 LOGE("failed to create input-selector");
1281 g_object_set(selector, "sync-streams", TRUE, NULL);
1283 srcpad = gst_element_get_static_pad(selector, "src");
1285 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1286 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1287 __mmplayer_gst_combiner_blocked, NULL, NULL);
1288 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1289 __mmplayer_gst_combiner_event_probe, player, NULL);
1291 gst_element_set_state(selector, GST_STATE_PAUSED);
1293 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1294 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1295 LOGE("failed to add selector to pipeline");
1297 if (player->track[stream_type].block_id != 0)
1298 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1299 player->track[stream_type].block_id = 0;
1301 if (player->track[stream_type].event_probe_id != 0)
1302 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1303 player->track[stream_type].event_probe_id = 0;
1305 gst_object_unref(GST_OBJECT(srcpad));
1307 gst_element_set_state(selector, GST_STATE_NULL);
1308 gst_object_unref(GST_OBJECT(selector));
1312 gst_object_unref(GST_OBJECT(srcpad));
1314 player->pipeline->mainbin[elem_idx].id = elem_idx;
1315 player->pipeline->mainbin[elem_idx].gst = selector;
1322 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1324 mmplayer_t *player = (mmplayer_t *)data;
1325 GstElement *combiner = NULL;
1326 GstCaps *caps = NULL;
1327 GstStructure *str = NULL;
1328 const gchar *name = NULL;
1329 GstPad *sinkpad = NULL;
1330 gboolean first_track = FALSE;
1331 gboolean caps_ret = TRUE;
1333 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1334 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1337 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1338 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1340 LOGD("pad-added signal handling");
1342 /* get mimetype from caps */
1343 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1347 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1349 LOGD("detected mimetype : %s", name);
1352 if (strstr(name, "video")) {
1354 gchar *caps_str = NULL;
1356 caps_str = gst_caps_to_string(caps);
1357 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1358 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1359 player->set_mode.video_zc = true;
1361 MMPLAYER_FREEIF(caps_str);
1363 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1364 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1366 LOGD("surface type : %d", stype);
1368 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1369 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1373 /* in case of exporting video frame, it requires the 360 video filter.
1374 * it will be handled in _no_more_pads(). */
1375 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1376 __mmplayer_gst_make_fakesink(player, pad, name);
1380 if (MMPLAYER_USE_DECODEBIN(player)) {
1381 LOGD("video selector is required");
1382 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1384 LOGD("video concat is required");
1385 elem_idx = MMPLAYER_M_V_CONCAT;
1387 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1388 } else if (strstr(name, "audio")) {
1389 gint samplerate = 0;
1392 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1393 if (player->build_audio_offload)
1394 player->no_more_pad = TRUE; /* remove state holder */
1395 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1399 gst_structure_get_int(str, "rate", &samplerate);
1400 gst_structure_get_int(str, "channels", &channels);
1402 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1403 __mmplayer_gst_make_fakesink(player, pad, name);
1406 if (MMPLAYER_USE_DECODEBIN(player)) {
1407 LOGD("audio selector is required");
1408 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1410 LOGD("audio concat is required");
1411 elem_idx = MMPLAYER_M_A_CONCAT;
1413 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1415 } else if (strstr(name, "text")) {
1416 if (MMPLAYER_USE_DECODEBIN(player)) {
1417 LOGD("text selector is required");
1418 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1420 LOGD("text concat is required");
1421 elem_idx = MMPLAYER_M_T_CONCAT;
1423 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1425 LOGE("invalid caps info");
1429 /* check selector and create it */
1430 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1431 if (MMPLAYER_USE_DECODEBIN(player))
1432 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1434 combiner = __mmplayer_gst_make_concat(player, elem_idx, stream_type);
1440 LOGD("Combiner element is already created.");
1444 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1446 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1448 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1449 LOGE("failed to link combiner");
1450 gst_object_unref(GST_OBJECT(combiner));
1455 if (MMPLAYER_USE_DECODEBIN(player)) {
1456 LOGD("this track will be activated");
1457 g_object_set(combiner, "active-pad", sinkpad, NULL);
1461 if (MMPLAYER_USE_DECODEBIN(player)) {
1462 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1464 /* apply the text track information */
1465 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1466 mm_player_set_attribute((MMHandleType)player, NULL,
1467 "content_text_track_num", player->track[stream_type].total_track_num,
1468 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1469 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1476 gst_caps_unref(caps);
1479 gst_object_unref(GST_OBJECT(sinkpad));
1483 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1488 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1490 GstPad *srcpad = NULL;
1493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1495 LOGD("type %d", type);
1498 LOGD("there is no %d track", type);
1502 srcpad = gst_element_get_static_pad(combiner, "src");
1504 LOGE("failed to get srcpad from combiner");
1508 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1510 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1512 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1513 if (player->track[type].block_id) {
1514 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1515 player->track[type].block_id = 0;
1519 gst_object_unref(GST_OBJECT(srcpad));
1528 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1530 gint active_index = 0;
1533 MMPLAYER_RETURN_IF_FAIL(player);
1535 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1537 /* change track to active pad */
1538 active_index = player->track[type].active_track_index;
1539 if ((active_index != DEFAULT_TRACK_INDEX) &&
1540 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1541 LOGW("failed to change %d type track to %d", type, active_index);
1542 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1546 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1547 mm_player_set_attribute((MMHandleType)player, NULL,
1548 "content_text_track_num", player->track[type].total_track_num,
1549 "current_text_track_index", player->track[type].active_track_index, NULL);
1556 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1559 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1561 if (!audio_selector) {
1562 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1564 /* in case the source is changed, output can be changed. */
1565 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1566 LOGD("remove previous audiobin if it exist");
1568 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1569 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1571 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1572 MMPLAYER_FREEIF(player->pipeline->audiobin);
1575 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1576 _mmplayer_pipeline_complete(NULL, player);
1581 /* apply the audio track information */
1582 if (MMPLAYER_USE_DECODEBIN(player))
1583 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1585 /* create audio sink path */
1586 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1587 LOGE("failed to create audio sink path");
1596 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1599 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1601 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1602 LOGD("text path is not supported");
1606 /* apply the text track information */
1607 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1609 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1610 player->has_closed_caption = TRUE;
1612 /* create text decode path */
1613 player->no_more_pad = TRUE;
1615 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1616 LOGE("failed to create text sink path");
1625 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1627 gint64 dur_bytes = 0L;
1630 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1631 player->pipeline->mainbin && player->streamer, FALSE);
1633 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1634 LOGE("fail to get duration.");
1636 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1637 * use file information was already set on Q2 when it was created. */
1638 _mm_player_streaming_set_queue2(player->streamer,
1639 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1640 TRUE, /* use_buffering */
1641 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1642 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1649 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1651 mmplayer_t *player = NULL;
1652 GstElement *video_selector = NULL;
1653 GstElement *audio_selector = NULL;
1654 GstElement *text_selector = NULL;
1657 player = (mmplayer_t *)data;
1659 LOGD("no-more-pad signal handling");
1661 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1662 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1663 LOGW("player is shutting down");
1667 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1668 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1669 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1670 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1671 LOGE("failed to set queue2 buffering");
1676 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1677 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1678 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1680 if (!video_selector && !audio_selector && !text_selector) {
1681 LOGW("there is no selector");
1682 player->no_more_pad = TRUE;
1686 /* create video path followed by video-select */
1687 if (video_selector && !audio_selector && !text_selector)
1688 player->no_more_pad = TRUE;
1690 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1693 /* create audio path followed by audio-select */
1694 if (audio_selector && !text_selector)
1695 player->no_more_pad = TRUE;
1697 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1700 /* create text path followed by text-select */
1701 __mmplayer_create_text_sink_path(player, text_selector);
1704 _mmplayer_set_reconfigure_state(player, FALSE);
1709 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1711 gboolean ret = FALSE;
1712 GstElement *pipeline = NULL;
1713 GstPad *sinkpad = NULL;
1716 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1719 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1721 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1723 LOGE("failed to get pad from sinkbin");
1729 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1730 LOGE("failed to link sinkbin for reusing");
1731 goto EXIT; /* exit either pass or fail */
1735 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1736 LOGE("failed to set state(READY) to sinkbin");
1741 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1742 LOGE("failed to add sinkbin to pipeline");
1747 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1748 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1753 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1754 LOGE("failed to set state(PAUSED) to sinkbin");
1763 gst_object_unref(GST_OBJECT(sinkpad));
1771 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1773 mmplayer_t *player = NULL;
1774 GstCaps *caps = NULL;
1775 gchar *caps_str = NULL;
1776 GstStructure *str = NULL;
1777 const gchar *name = NULL;
1778 GstElement *sinkbin = NULL;
1779 gboolean reusing = FALSE;
1780 gboolean caps_ret = TRUE;
1781 gchar *sink_pad_name = "sink";
1784 player = (mmplayer_t *)data;
1787 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1788 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1789 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1791 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1795 gst_caps_unref(caps);
1796 caps = gst_caps_ref(ref_caps);
1799 caps_str = gst_caps_to_string(caps);
1801 LOGD("detected mimetype : %s", name);
1803 if (strstr(name, "audio")) {
1804 if (player->pipeline->audiobin == NULL) {
1805 const gchar *audio_format = gst_structure_get_string(str, "format");
1807 LOGD("original audio format %s", audio_format);
1808 mm_player_set_attribute((MMHandleType)player, NULL,
1809 "content_audio_format", audio_format, strlen(audio_format), NULL);
1812 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1813 LOGE("failed to create audiobin. continuing without audio");
1817 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1818 LOGD("creating audiobin success");
1821 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1822 LOGD("reusing audiobin");
1823 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1825 } else if (strstr(name, "video")) {
1826 /* 1. zero copy is updated at _decode_pad_added()
1827 * 2. NULL surface type is handled in _decode_pad_added() */
1828 LOGD("zero copy %d", player->set_mode.video_zc);
1829 if (player->pipeline->videobin == NULL) {
1830 int surface_type = 0;
1831 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1832 LOGD("display_surface_type (%d)", surface_type);
1834 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1835 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1836 LOGE("failed to acquire video overlay resource");
1840 player->interrupted_by_resource = FALSE;
1842 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1843 LOGE("failed to create videobin. continuing without video");
1847 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1848 LOGD("creating videosink bin success");
1851 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1852 LOGD("re-using videobin");
1853 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1855 } else if (strstr(name, "text")) {
1856 if (player->pipeline->textbin == NULL) {
1857 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1858 LOGE("failed to create text sink bin. continuing without text");
1862 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1863 player->textsink_linked = 1;
1864 LOGD("creating textsink bin success");
1866 if (!player->textsink_linked) {
1867 LOGD("re-using textbin");
1869 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1870 player->textsink_linked = 1;
1872 /* linked textbin exist which means that the external subtitle path exist already */
1873 LOGW("ignoring internal subtitle since external subtitle is available");
1876 sink_pad_name = "text_sink";
1878 LOGW("unknown mime type %s, ignoring it", name);
1882 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1885 LOGD("[handle: %p] success to create and link sink bin", player);
1887 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1888 * streaming task. if the task blocked, then buffer will not flow to the next element
1889 *(autoplugging element). so this is special hack for streaming. please try to remove it
1891 /* dec stream count. we can remove fakesink if it's zero */
1892 if (player->num_dynamic_pad)
1893 player->num_dynamic_pad--;
1895 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1897 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1898 _mmplayer_pipeline_complete(NULL, player);
1902 MMPLAYER_FREEIF(caps_str);
1905 gst_caps_unref(caps);
1911 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1913 int required_angle = 0; /* Angle required for straight view */
1914 int rotation_angle = 0;
1916 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1917 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1919 /* Counter clockwise */
1920 switch (orientation) {
1925 required_angle = 270;
1928 required_angle = 180;
1931 required_angle = 90;
1935 rotation_angle = display_angle + required_angle;
1936 if (rotation_angle >= 360)
1937 rotation_angle -= 360;
1939 /* check if supported or not */
1940 if (rotation_angle % 90) {
1941 LOGD("not supported rotation angle = %d", rotation_angle);
1945 switch (rotation_angle) {
1947 *value = MM_DISPLAY_ROTATION_NONE;
1950 *value = MM_DISPLAY_ROTATION_90;
1953 *value = MM_DISPLAY_ROTATION_180;
1956 *value = MM_DISPLAY_ROTATION_270;
1960 LOGD("setting rotation property value : %d", *value);
1966 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1968 int display_rotation = 0;
1969 gchar *org_orient = NULL;
1970 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1973 LOGE("cannot get content attribute");
1974 return MM_ERROR_PLAYER_INTERNAL;
1977 if (display_angle) {
1978 /* update user rotation */
1979 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1981 /* Counter clockwise */
1982 switch (display_rotation) {
1983 case MM_DISPLAY_ROTATION_NONE:
1986 case MM_DISPLAY_ROTATION_90:
1987 *display_angle = 90;
1989 case MM_DISPLAY_ROTATION_180:
1990 *display_angle = 180;
1992 case MM_DISPLAY_ROTATION_270:
1993 *display_angle = 270;
1996 LOGW("wrong angle type : %d", display_rotation);
1999 LOGD("check user angle: %d", *display_angle);
2003 /* Counter clockwise */
2004 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2007 if (!strcmp(org_orient, "rotate-90"))
2009 else if (!strcmp(org_orient, "rotate-180"))
2011 else if (!strcmp(org_orient, "rotate-270"))
2014 LOGD("original rotation is %s", org_orient);
2016 LOGD("content_video_orientation get fail");
2019 LOGD("check orientation: %d", *orientation);
2022 return MM_ERROR_NONE;
2025 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2027 int rotation_value = 0;
2028 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2029 int display_angle = 0;
2032 /* check video sinkbin is created */
2033 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2036 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2038 /* get rotation value to set */
2039 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2040 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2041 LOGD("set video param : rotate %d", rotation_value);
2044 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2046 MMHandleType attrs = 0;
2050 /* check video sinkbin is created */
2051 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2052 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2055 attrs = MMPLAYER_GET_ATTRS(player);
2056 MMPLAYER_RETURN_IF_FAIL(attrs);
2058 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2059 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2060 LOGD("set video param : visible %d", visible);
2063 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2065 MMHandleType attrs = 0;
2066 int display_method = 0;
2069 /* check video sinkbin is created */
2070 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2073 attrs = MMPLAYER_GET_ATTRS(player);
2074 MMPLAYER_RETURN_IF_FAIL(attrs);
2076 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2077 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2078 LOGD("set video param : method %d", display_method);
2081 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2083 MMHandleType attrs = 0;
2087 /* check video sinkbin is created */
2088 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2091 attrs = MMPLAYER_GET_ATTRS(player);
2092 MMPLAYER_RETURN_IF_FAIL(attrs);
2094 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2095 MMPLAYER_RETURN_IF_FAIL(handle);
2097 gst_video_overlay_set_video_roi_area(
2098 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2099 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2100 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2101 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2104 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2106 MMHandleType attrs = 0;
2111 int win_roi_width = 0;
2112 int win_roi_height = 0;
2115 /* check video sinkbin is created */
2116 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2119 attrs = MMPLAYER_GET_ATTRS(player);
2120 MMPLAYER_RETURN_IF_FAIL(attrs);
2122 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2123 MMPLAYER_RETURN_IF_FAIL(handle);
2125 /* It should be set after setting window */
2126 mm_attrs_multiple_get(attrs, NULL,
2127 "display_win_roi_x", &win_roi_x,
2128 "display_win_roi_y", &win_roi_y,
2129 "display_win_roi_width", &win_roi_width,
2130 "display_win_roi_height", &win_roi_height, NULL);
2132 /* After setting window handle, set display roi area */
2133 gst_video_overlay_set_display_roi_area(
2134 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2135 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2136 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2137 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2140 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2142 MMHandleType attrs = 0;
2143 gchar *handle = NULL;
2145 /* check video sinkbin is created */
2146 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2149 attrs = MMPLAYER_GET_ATTRS(player);
2150 MMPLAYER_RETURN_IF_FAIL(attrs);
2152 /* common case if using overlay surface */
2153 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2154 MMPLAYER_RETURN_IF_FAIL(handle);
2156 gst_video_overlay_set_wl_window_exported_shell_handle(
2157 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2159 LOGD("set video param: exported_shell_handle (%s)", handle);
2162 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2164 MMHandleType attrs = 0;
2167 /* check video sinkbin is created */
2168 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2171 attrs = MMPLAYER_GET_ATTRS(player);
2172 MMPLAYER_RETURN_IF_FAIL(attrs);
2174 /* common case if using overlay surface */
2175 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2176 MMPLAYER_RETURN_IF_FAIL(handle);
2178 /* default is using wl_surface_id */
2179 LOGD("set video param : wl_surface_id %d", handle);
2180 gst_video_overlay_set_wl_window_wl_surface_id(
2181 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2186 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2188 gboolean update_all_param = FALSE;
2189 int curr_type = MM_DISPLAY_SURFACE_NUM;
2193 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2194 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2195 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2196 LOGW("videosink is not ready yet");
2197 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2200 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2202 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2203 LOGE("current type(%d) is wrong", curr_type);
2204 return MM_ERROR_PLAYER_INTERNAL;
2207 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2208 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2209 return MM_ERROR_PLAYER_INTERNAL;
2212 LOGD("param_name : %s", param_name);
2213 if (!g_strcmp0(param_name, "update_all_param"))
2214 update_all_param = TRUE;
2216 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2217 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2219 return MM_ERROR_NONE;
2221 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2222 __mmplayer_video_param_set_display_overlay(player);
2223 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2224 __mmplayer_video_param_set_display_method(player);
2225 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2226 __mmplayer_video_param_set_display_visible(player);
2227 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2228 __mmplayer_video_param_set_display_rotation(player);
2229 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2230 __mmplayer_video_param_set_roi_area(player);
2231 if (update_all_param)
2232 __mmplayer_video_param_set_video_roi_area(player);
2235 return MM_ERROR_NONE;
2238 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2240 gboolean disable_overlay = FALSE;
2243 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2244 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2245 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2247 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2248 LOGW("Display control is not supported");
2249 return MM_ERROR_PLAYER_INTERNAL;
2252 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2254 if (disable == (bool)disable_overlay) {
2255 LOGE("It's the same with current setting: (%d)", disable);
2256 return MM_ERROR_NONE;
2260 LOGE("disable overlay");
2261 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2263 /* release overlay resource */
2264 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2265 LOGE("failed to release overlay resource");
2266 return MM_ERROR_PLAYER_INTERNAL;
2269 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2270 LOGE("failed to acquire video overlay resource");
2271 return MM_ERROR_PLAYER_INTERNAL;
2273 player->interrupted_by_resource = FALSE;
2275 LOGD("enable overlay");
2276 __mmplayer_video_param_set_display_overlay(player);
2277 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2278 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2282 return MM_ERROR_NONE;
2286 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2288 int ret = MM_ERROR_NONE;
2289 mmplayer_t *player = (mmplayer_t *)hplayer;
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2294 if (MMPLAYER_USE_DECODEBIN(player)) {
2295 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2300 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2301 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2302 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2304 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2306 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2308 /* release decoder resource */
2309 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2310 LOGE("failed to release video decoder resources");
2311 return MM_ERROR_PLAYER_INTERNAL;
2313 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2315 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2319 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2326 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2328 GList *bucket = element_bucket;
2329 mmplayer_gst_element_t *element = NULL;
2330 mmplayer_gst_element_t *prv_element = NULL;
2331 GstElement *tee_element = NULL;
2332 gint successful_link_count = 0;
2336 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2338 prv_element = (mmplayer_gst_element_t *)bucket->data;
2339 bucket = bucket->next;
2341 for (; bucket; bucket = bucket->next) {
2342 element = (mmplayer_gst_element_t *)bucket->data;
2344 if (element && element->gst) {
2345 if (prv_element && prv_element->gst) {
2346 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2348 prv_element->gst = tee_element;
2350 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2351 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2352 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2356 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2357 LOGD("linking [%s] to [%s] success",
2358 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2359 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2360 successful_link_count++;
2361 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2362 LOGD("keep audio-tee element for next audio pipeline branch");
2363 tee_element = prv_element->gst;
2366 LOGD("linking [%s] to [%s] failed",
2367 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2368 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2374 prv_element = element;
2379 return successful_link_count;
2383 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2385 GList *bucket = element_bucket;
2386 mmplayer_gst_element_t *element = NULL;
2387 int successful_add_count = 0;
2391 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2392 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2394 for (; bucket; bucket = bucket->next) {
2395 element = (mmplayer_gst_element_t *)bucket->data;
2397 if (element && element->gst) {
2398 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2399 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2400 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2401 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2404 successful_add_count++;
2410 return successful_add_count;
2414 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2416 mmplayer_t *player = (mmplayer_t *)data;
2417 GstCaps *caps = NULL;
2418 GstStructure *str = NULL;
2420 gboolean caps_ret = TRUE;
2424 MMPLAYER_RETURN_IF_FAIL(pad);
2425 MMPLAYER_RETURN_IF_FAIL(unused);
2426 MMPLAYER_RETURN_IF_FAIL(data);
2428 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2432 LOGD("name = %s", name);
2434 if (strstr(name, "audio")) {
2435 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2437 if (player->audio_stream_changed_cb) {
2438 LOGE("call the audio stream changed cb");
2439 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2441 } else if (strstr(name, "video")) {
2442 if ((name = gst_structure_get_string(str, "format")))
2443 player->set_mode.video_zc = name[0] == 'S';
2445 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2446 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2448 LOGW("invalid caps info");
2453 gst_caps_unref(caps);
2461 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2466 MMPLAYER_RETURN_IF_FAIL(player);
2468 if (player->audio_stream_buff_list) {
2469 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2470 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2473 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2474 __mmplayer_audio_stream_send_data(player, tmp);
2476 MMPLAYER_FREEIF(tmp->pcm_data);
2477 MMPLAYER_FREEIF(tmp);
2480 g_list_free(player->audio_stream_buff_list);
2481 player->audio_stream_buff_list = NULL;
2488 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2490 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2493 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2495 audio_stream.bitrate = a_buffer->bitrate;
2496 audio_stream.channel = a_buffer->channel;
2497 audio_stream.channel_mask = a_buffer->channel_mask;
2498 audio_stream.data_size = a_buffer->data_size;
2499 audio_stream.data = a_buffer->pcm_data;
2500 audio_stream.pcm_format = a_buffer->pcm_format;
2502 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2504 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2510 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2512 mmplayer_t *player = (mmplayer_t *)data;
2513 const gchar *pcm_format = NULL;
2516 guint64 channel_mask = 0;
2517 void *a_data = NULL;
2519 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2520 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2524 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2526 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2527 a_data = mapinfo.data;
2528 a_size = mapinfo.size;
2530 GstCaps *caps = gst_pad_get_current_caps(pad);
2531 GstStructure *structure = gst_caps_get_structure(caps, 0);
2533 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2535 pcm_format = gst_structure_get_string(structure, "format");
2536 gst_structure_get_int(structure, "rate", &rate);
2537 gst_structure_get_int(structure, "channels", &channel);
2538 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2539 gst_caps_unref(GST_CAPS(caps));
2541 /* In case of the sync is false, use buffer list. *
2542 * The num of buffer list depends on the num of audio channels */
2543 if (player->audio_stream_buff_list) {
2544 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2545 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2547 if (channel_mask == tmp->channel_mask) {
2549 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2551 if (tmp->data_size + a_size < tmp->buff_size) {
2552 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2553 tmp->data_size += a_size;
2555 /* send data to client */
2556 __mmplayer_audio_stream_send_data(player, tmp);
2558 if (a_size > tmp->buff_size) {
2559 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2560 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2561 if (tmp->pcm_data == NULL) {
2562 LOGE("failed to realloc data.");
2565 tmp->buff_size = a_size;
2567 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2568 memcpy(tmp->pcm_data, a_data, a_size);
2569 tmp->data_size = a_size;
2574 LOGE("data is empty in list.");
2580 /* create new audio stream data for newly found audio channel */
2581 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2582 if (a_buffer == NULL) {
2583 LOGE("failed to alloc data.");
2586 a_buffer->bitrate = rate;
2587 a_buffer->channel = channel;
2588 a_buffer->channel_mask = channel_mask;
2589 a_buffer->data_size = a_size;
2590 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2592 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2593 /* If sync is FALSE, use buffer list to reduce the IPC. */
2594 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2595 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2596 if (a_buffer->pcm_data == NULL) {
2597 LOGE("failed to alloc data.");
2598 MMPLAYER_FREEIF(a_buffer);
2601 memcpy(a_buffer->pcm_data, a_data, a_size);
2603 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2605 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2607 /* If sync is TRUE, send data directly. */
2608 a_buffer->pcm_data = a_data;
2609 __mmplayer_audio_stream_send_data(player, a_buffer);
2610 MMPLAYER_FREEIF(a_buffer);
2614 gst_buffer_unmap(buffer, &mapinfo);
2619 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2621 mmplayer_t *player = (mmplayer_t *)data;
2622 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2623 GstPad *sinkpad = NULL;
2624 GstElement *queue = NULL, *sink = NULL;
2627 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2629 queue = gst_element_factory_make("queue", NULL);
2630 if (queue == NULL) {
2631 LOGD("fail make queue");
2635 sink = gst_element_factory_make("fakesink", NULL);
2637 LOGD("fail make fakesink");
2641 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2643 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2644 LOGW("failed to link queue & sink");
2648 sinkpad = gst_element_get_static_pad(queue, "sink");
2650 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2651 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2655 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2657 gst_object_unref(sinkpad);
2658 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2659 g_object_set(sink, "sync", TRUE, NULL);
2660 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2662 /* keep the first sink reference only */
2663 if (!audiobin[MMPLAYER_A_SINK].gst) {
2664 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2665 audiobin[MMPLAYER_A_SINK].gst = sink;
2669 _mmplayer_add_signal_connection(player,
2671 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2673 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2676 __mmplayer_add_sink(player, sink, FALSE);
2678 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2679 LOGE("failed to sync state");
2683 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2684 LOGE("failed to sync state");
2692 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2694 gst_object_unref(GST_OBJECT(queue));
2698 gst_object_unref(GST_OBJECT(sink));
2702 gst_object_unref(GST_OBJECT(sinkpad));
2710 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2712 mmplayer_t *player = (mmplayer_t *)data;
2715 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2717 player->no_more_pad = TRUE;
2718 _mmplayer_pipeline_complete(NULL, player);
2725 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2727 #define MAX_PROPS_LEN 128
2728 mmplayer_gst_element_t *audiobin = NULL;
2729 gint latency_mode = 0;
2730 gchar *stream_type = NULL;
2731 gchar *latency = NULL;
2733 gchar stream_props[MAX_PROPS_LEN] = {0,};
2734 GstStructure *props = NULL;
2737 * It should be set after player creation through attribute.
2738 * But, it can not be changed during playing.
2741 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2743 audiobin = player->pipeline->audiobin;
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2746 if (player->sound.mute) {
2747 LOGD("mute enabled");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2751 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2752 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2755 snprintf(stream_props, sizeof(stream_props) - 1,
2756 "props,application.process.id.origin=%d", player->client_pid);
2758 snprintf(stream_props, sizeof(stream_props) - 1,
2759 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2760 stream_type, stream_id, player->client_pid);
2762 props = gst_structure_from_string(stream_props, NULL);
2763 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2764 LOGI("props result[%s].", stream_props);
2765 gst_structure_free(props);
2767 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2769 switch (latency_mode) {
2770 case AUDIO_LATENCY_MODE_LOW:
2771 latency = g_strdup("low");
2773 case AUDIO_LATENCY_MODE_MID:
2774 latency = g_strdup("mid");
2776 case AUDIO_LATENCY_MODE_HIGH:
2777 latency = g_strdup("high");
2780 latency = g_strdup("mid");
2784 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2786 LOGD("audiosink property - latency=%s", latency);
2788 MMPLAYER_FREEIF(latency);
2794 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2796 mmplayer_gst_element_t *audiobin = NULL;
2799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2800 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2802 audiobin = player->pipeline->audiobin;
2804 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2805 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2806 LOGE("failed to create media stream info");
2807 return MM_ERROR_PLAYER_INTERNAL;
2810 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2812 if (player->video360_yaw_radians <= M_PI &&
2813 player->video360_yaw_radians >= -M_PI &&
2814 player->video360_pitch_radians <= M_PI_2 &&
2815 player->video360_pitch_radians >= -M_PI_2) {
2816 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2817 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2818 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2819 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2820 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2821 "source-orientation-y", player->video360_metadata.init_view_heading,
2822 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2826 return MM_ERROR_NONE;
2830 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2832 mmplayer_gst_element_t *audiobin = NULL;
2833 GstPad *sink_pad = NULL;
2834 GstCaps *acaps = NULL;
2836 int pitch_control = 0;
2837 double pitch_value = 1.0;
2840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2841 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2843 audiobin = player->pipeline->audiobin;
2845 LOGD("make element for normal audio playback");
2847 /* audio bin structure for playback. {} means optional.
2848 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2850 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2851 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2854 /* for pitch control */
2855 mm_attrs_multiple_get(player->attrs, NULL,
2856 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2857 MM_PLAYER_PITCH_VALUE, &pitch_value,
2860 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2861 if (pitch_control && (player->videodec_linked == 0)) {
2862 GstElementFactory *factory;
2864 factory = gst_element_factory_find("pitch");
2866 gst_object_unref(factory);
2869 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2872 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2875 LOGW("there is no pitch element");
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2882 /* replaygain volume */
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2884 if (player->sound.rg_enable)
2885 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2887 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2890 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2892 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2893 /* currently, only openalsink uses volume element */
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2895 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2897 if (player->sound.mute) {
2898 LOGD("mute enabled");
2899 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2903 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2905 /* audio effect element. if audio effect is enabled */
2906 if ((strcmp(player->ini.audioeffect_element, ""))
2908 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2909 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2911 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2913 if ((!player->bypass_audio_effect)
2914 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2915 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2916 if (!_mmplayer_audio_effect_custom_apply(player))
2917 LOGI("apply audio effect(custom) setting success");
2921 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2922 && (player->set_mode.rich_audio)) {
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2927 /* create audio sink */
2928 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2929 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2930 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2932 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2933 if (player->is_360_feature_enabled &&
2934 player->is_content_spherical &&
2936 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2937 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2938 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2940 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2942 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2945 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2946 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2947 gst_caps_unref(acaps);
2949 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2951 player->is_openal_plugin_used = TRUE;
2953 if (player->is_360_feature_enabled && player->is_content_spherical)
2954 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2955 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2958 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2959 (player->videodec_linked && player->ini.use_system_clock)) {
2960 LOGD("system clock will be used.");
2961 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2964 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2965 __mmplayer_gst_set_pulsesink_property(player);
2966 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2967 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2972 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2973 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2975 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2976 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2977 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2978 gst_object_unref(GST_OBJECT(sink_pad));
2980 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2983 return MM_ERROR_NONE;
2985 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2987 return MM_ERROR_PLAYER_INTERNAL;
2991 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2993 mmplayer_gst_element_t *audiobin = NULL;
2994 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2996 gchar *dst_format = NULL;
2998 int dst_samplerate = 0;
2999 int dst_channels = 0;
3000 GstCaps *caps = NULL;
3001 char *caps_str = NULL;
3004 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3005 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3007 audiobin = player->pipeline->audiobin;
3009 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
3011 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
3013 [case 1] extract interleave audio pcm without playback
3014 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
3015 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
3017 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
3019 [case 2] deinterleave for each channel without playback
3020 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
3021 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
3023 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
3024 - fakesink (sync or not)
3027 [case 3] [case 1(sync only)] + playback
3028 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3030 * src - ... - tee - queue1 - playback path
3031 - queue2 - [case1 pipeline with sync]
3033 [case 4] [case 2(sync only)] + playback
3034 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3036 * src - ... - tee - queue1 - playback path
3037 - queue2 - [case2 pipeline with sync]
3041 /* 1. create tee and playback path
3042 'tee' should be added at first to copy the decoded stream
3044 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3045 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3046 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3048 /* tee - path 1 : for playback path */
3049 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3050 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3052 /* tee - path 2 : for extract path */
3053 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3054 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3057 /* if there is tee, 'tee - path 2' is linked here */
3059 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3062 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3064 /* 2. decide the extract pcm format */
3065 mm_attrs_multiple_get(player->attrs, NULL,
3066 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3067 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3068 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3071 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3072 dst_format, dst_len, dst_samplerate, dst_channels);
3074 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3075 mm_attrs_multiple_get(player->attrs, NULL,
3076 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3077 "content_audio_samplerate", &dst_samplerate,
3078 "content_audio_channels", &dst_channels,
3081 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3082 dst_format, dst_len, dst_samplerate, dst_channels);
3084 /* If there is no enough information, set it to platform default value. */
3085 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3086 LOGD("set platform default format");
3087 dst_format = DEFAULT_PCM_OUT_FORMAT;
3089 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3090 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3093 /* 3. create capsfilter */
3094 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3095 caps = gst_caps_new_simple("audio/x-raw",
3096 "format", G_TYPE_STRING, dst_format,
3097 "rate", G_TYPE_INT, dst_samplerate,
3098 "channels", G_TYPE_INT, dst_channels,
3101 caps_str = gst_caps_to_string(caps);
3102 LOGD("new caps : %s", caps_str);
3104 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3107 gst_caps_unref(caps);
3108 MMPLAYER_FREEIF(caps_str);
3110 /* 4-1. create deinterleave to extract pcm for each channel */
3111 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3112 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3113 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3115 /* audiosink will be added after getting signal for each channel */
3116 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3117 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3118 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3119 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3120 player->no_more_pad = FALSE;
3122 /* 4-2. create fakesink to extract interleaved pcm */
3123 LOGD("add audio fakesink for interleaved audio");
3124 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3125 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3126 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3127 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3129 _mmplayer_add_signal_connection(player,
3130 G_OBJECT(audiobin[extract_sink_id].gst),
3131 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3133 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3136 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3140 return MM_ERROR_NONE;
3142 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3144 return MM_ERROR_PLAYER_INTERNAL;
3148 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3150 int ret = MM_ERROR_NONE;
3151 mmplayer_gst_element_t *audiobin = NULL;
3152 GList *element_bucket = NULL;
3155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3156 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3158 audiobin = player->pipeline->audiobin;
3160 if (player->build_audio_offload) { /* skip all the audio filters */
3161 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3163 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3164 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3165 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3167 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3171 /* FIXME: need to mention the supportable condition at API reference */
3172 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3173 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3175 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3177 if (ret != MM_ERROR_NONE)
3180 LOGD("success to make audio bin element");
3181 *bucket = element_bucket;
3184 return MM_ERROR_NONE;
3187 LOGE("failed to make audio bin element");
3188 g_list_free(element_bucket);
3192 return MM_ERROR_PLAYER_INTERNAL;
3196 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3198 mmplayer_gst_element_t *first_element = NULL;
3199 mmplayer_gst_element_t *audiobin = NULL;
3201 GstPad *ghostpad = NULL;
3202 GList *element_bucket = NULL;
3206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3209 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3211 LOGE("failed to allocate memory for audiobin");
3212 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3216 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3217 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3218 if (!audiobin[MMPLAYER_A_BIN].gst) {
3219 LOGE("failed to create audiobin");
3224 player->pipeline->audiobin = audiobin;
3226 /* create audio filters and audiosink */
3227 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3230 /* adding created elements to bin */
3231 LOGD("adding created elements to bin");
3232 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3235 /* linking elements in the bucket by added order. */
3236 LOGD("Linking elements in the bucket by added order.");
3237 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3240 /* get first element's sinkpad for creating ghostpad */
3241 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3242 if (!first_element) {
3243 LOGE("failed to get first elem");
3247 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3249 LOGE("failed to get pad from first element of audiobin");
3253 ghostpad = gst_ghost_pad_new("sink", pad);
3255 LOGE("failed to create ghostpad");
3259 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3260 LOGE("failed to add ghostpad to audiobin");
3264 gst_object_unref(pad);
3266 g_list_free(element_bucket);
3269 return MM_ERROR_NONE;
3272 LOGD("ERROR : releasing audiobin");
3275 gst_object_unref(GST_OBJECT(pad));
3278 gst_object_unref(GST_OBJECT(ghostpad));
3281 g_list_free(element_bucket);
3283 /* release element which are not added to bin */
3284 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3285 /* NOTE : skip bin */
3286 if (audiobin[i].gst) {
3287 GstObject *parent = NULL;
3288 parent = gst_element_get_parent(audiobin[i].gst);
3291 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3292 audiobin[i].gst = NULL;
3294 gst_object_unref(GST_OBJECT(parent));
3298 /* release audiobin with it's children */
3299 if (audiobin[MMPLAYER_A_BIN].gst)
3300 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3302 MMPLAYER_FREEIF(audiobin);
3304 player->pipeline->audiobin = NULL;
3306 return MM_ERROR_PLAYER_INTERNAL;
3310 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3312 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3316 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3318 int ret = MM_ERROR_NONE;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3321 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3323 MMPLAYER_VIDEO_BO_LOCK(player);
3325 if (player->video_bo_list) {
3326 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3327 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3328 if (tmp && tmp->bo == bo) {
3330 LOGD("release bo %p", bo);
3331 tbm_bo_unref(tmp->bo);
3332 MMPLAYER_VIDEO_BO_UNLOCK(player);
3333 MMPLAYER_VIDEO_BO_SIGNAL(player);
3338 /* hw codec is running or the list was reset for DRC. */
3339 LOGW("there is no bo list.");
3341 MMPLAYER_VIDEO_BO_UNLOCK(player);
3343 LOGW("failed to find bo %p", bo);
3347 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3353 tbm_bo_unref(tmp->bo);
3358 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3361 MMPLAYER_RETURN_IF_FAIL(player);
3363 MMPLAYER_VIDEO_BO_LOCK(player);
3364 if (player->video_bo_list) {
3365 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3366 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3367 player->video_bo_list = NULL;
3369 player->video_bo_size = 0;
3370 MMPLAYER_VIDEO_BO_UNLOCK(player);
3377 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3380 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3381 gboolean ret = TRUE;
3382 gint64 end_time = 0;
3384 /* check DRC, if it is, destroy the prev bo list to create again */
3385 if (player->video_bo_size != size) {
3386 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3387 __mmplayer_video_stream_destroy_bo_list(player);
3388 player->video_bo_size = size;
3391 MMPLAYER_VIDEO_BO_LOCK(player);
3393 if ((!player->video_bo_list) ||
3394 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3396 /* create bo list */
3398 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3400 if (player->video_bo_list) {
3401 /* if bo list did not created all, try it again. */
3402 idx = g_list_length(player->video_bo_list);
3403 LOGD("bo list exist(len: %d)", idx);
3406 for (; idx < player->ini.num_of_video_bo; idx++) {
3407 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3409 LOGE("Fail to alloc bo_info.");
3412 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3414 LOGE("Fail to tbm_bo_alloc.");
3415 MMPLAYER_FREEIF(bo_info);
3418 bo_info->used = FALSE;
3419 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3422 /* update video num buffers */
3423 LOGD("video_num_buffers : %d", idx);
3424 mm_player_set_attribute((MMHandleType)player, NULL,
3425 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3426 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3430 MMPLAYER_VIDEO_BO_UNLOCK(player);
3435 if (player->ini.video_bo_timeout > 0)
3436 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3439 /* get bo from list*/
3440 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3441 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3442 if (tmp && (tmp->used == FALSE)) {
3443 LOGD("found bo %p to use", tmp->bo);
3445 MMPLAYER_VIDEO_BO_UNLOCK(player);
3446 return tbm_bo_ref(tmp->bo);
3450 if (player->ini.video_bo_timeout <= 0) {
3451 MMPLAYER_VIDEO_BO_WAIT(player);
3453 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3455 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3461 MMPLAYER_VIDEO_BO_UNLOCK(player);
3466 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3468 mmplayer_t *player = (mmplayer_t *)data;
3470 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3472 /* send prerolled pkt */
3473 player->video_stream_prerolled = false;
3475 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3477 /* not to send prerolled pkt again */
3478 player->video_stream_prerolled = true;
3482 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3484 mmplayer_t *player = (mmplayer_t *)data;
3485 mmplayer_video_decoded_data_info_t *stream = NULL;
3486 GstMemory *mem = NULL;
3489 MMPLAYER_RETURN_IF_FAIL(player);
3490 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3492 if (player->video_stream_prerolled) {
3493 player->video_stream_prerolled = false;
3494 LOGD("skip the prerolled pkt not to send it again");
3498 /* clear stream data structure */
3499 stream = __mmplayer_create_stream_from_pad(pad);
3501 LOGE("failed to alloc stream");
3505 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3507 /* set size and timestamp */
3508 mem = gst_buffer_peek_memory(buffer, 0);
3509 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3510 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3512 /* check zero-copy */
3513 if (player->set_mode.video_zc &&
3514 player->set_mode.video_export &&
3515 gst_is_tizen_memory(mem)) {
3516 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3517 stream->internal_buffer = gst_buffer_ref(buffer);
3518 } else { /* sw codec */
3519 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3522 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3526 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3527 LOGE("failed to send video decoded data.");
3534 LOGE("release video stream resource.");
3535 if (gst_is_tizen_memory(mem)) {
3537 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3539 tbm_bo_unref(stream->bo[i]);
3542 /* unref gst buffer */
3543 if (stream->internal_buffer)
3544 gst_buffer_unref(stream->internal_buffer);
3547 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3549 MMPLAYER_FREEIF(stream);
3554 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3556 mmplayer_gst_element_t *videobin = NULL;
3559 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3561 videobin = player->pipeline->videobin;
3563 /* Set spatial media metadata and/or user settings to the element.
3565 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3566 "projection-type", player->video360_metadata.projection_type, NULL);
3568 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3569 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3571 if (player->video360_metadata.full_pano_width_pixels &&
3572 player->video360_metadata.full_pano_height_pixels &&
3573 player->video360_metadata.cropped_area_image_width &&
3574 player->video360_metadata.cropped_area_image_height) {
3575 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3576 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3577 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3578 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3579 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3580 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3581 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3585 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3586 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3587 "horizontal-fov", player->video360_horizontal_fov,
3588 "vertical-fov", player->video360_vertical_fov, NULL);
3591 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3592 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3593 "zoom", 1.0f / player->video360_zoom, NULL);
3596 if (player->video360_yaw_radians <= M_PI &&
3597 player->video360_yaw_radians >= -M_PI &&
3598 player->video360_pitch_radians <= M_PI_2 &&
3599 player->video360_pitch_radians >= -M_PI_2) {
3600 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3601 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3602 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3603 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3604 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3605 "pose-yaw", player->video360_metadata.init_view_heading,
3606 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3609 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3610 "passthrough", !player->is_video360_enabled, NULL);
3617 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3619 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3620 GList *element_bucket = NULL;
3623 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3625 /* create video360 filter */
3626 if (player->is_360_feature_enabled && player->is_content_spherical) {
3627 LOGD("create video360 element");
3628 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3629 __mmplayer_gst_set_video360_property(player);
3633 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3634 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3635 player->set_mode.video_zc) {
3636 LOGD("skip creating the videoconv and rotator");
3637 return MM_ERROR_NONE;
3640 /* in case of sw codec & overlay surface type, except 360 playback.
3641 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3642 LOGD("create video converter: %s", video_csc);
3643 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3646 *bucket = element_bucket;
3648 return MM_ERROR_NONE;
3650 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3651 g_list_free(element_bucket);
3655 return MM_ERROR_PLAYER_INTERNAL;
3659 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3661 gchar *factory_name = NULL;
3663 switch (surface_type) {
3664 case MM_DISPLAY_SURFACE_OVERLAY:
3666 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3667 if (strlen(player->ini.videosink_element_overlay) > 0)
3668 factory_name = player->ini.videosink_element_overlay;
3670 case MM_DISPLAY_SURFACE_REMOTE:
3672 case MM_DISPLAY_SURFACE_NULL:
3673 if (strlen(player->ini.videosink_element_fake) > 0)
3674 factory_name = player->ini.videosink_element_fake;
3677 LOGE("unidentified surface type");
3681 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3682 return factory_name;
3686 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3688 gchar *factory_name = NULL;
3689 mmplayer_gst_element_t *videobin = NULL;
3694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3696 videobin = player->pipeline->videobin;
3697 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3699 attrs = MMPLAYER_GET_ATTRS(player);
3701 LOGE("cannot get content attribute");
3702 return MM_ERROR_PLAYER_INTERNAL;
3705 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3706 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3707 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3708 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3709 "use-tbm", use_tbm, NULL);
3712 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3713 return MM_ERROR_PLAYER_INTERNAL;
3715 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3718 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3719 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3722 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3724 LOGD("disable last-sample");
3725 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3728 if (player->set_mode.video_export) {
3730 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3731 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3732 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3734 _mmplayer_add_signal_connection(player,
3735 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3736 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3738 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3741 _mmplayer_add_signal_connection(player,
3742 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3743 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3745 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3749 if (videobin[MMPLAYER_V_SINK].gst) {
3750 GstPad *sink_pad = NULL;
3751 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3753 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3754 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3755 gst_object_unref(GST_OBJECT(sink_pad));
3757 LOGE("failed to get sink pad from videosink");
3761 return MM_ERROR_NONE;
3766 * - video overlay surface(arm/x86) : tizenwlsink
3769 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3772 GList *element_bucket = NULL;
3773 mmplayer_gst_element_t *first_element = NULL;
3774 mmplayer_gst_element_t *videobin = NULL;
3775 gchar *videosink_factory_name = NULL;
3778 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3781 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3783 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3785 player->pipeline->videobin = videobin;
3788 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3789 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3790 if (!videobin[MMPLAYER_V_BIN].gst) {
3791 LOGE("failed to create videobin");
3795 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3798 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3799 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3801 /* additional setting for sink plug-in */
3802 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3803 LOGE("failed to set video property");
3807 /* store it as it's sink element */
3808 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3810 /* adding created elements to bin */
3811 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3812 LOGE("failed to add elements");
3816 /* Linking elements in the bucket by added order */
3817 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3818 LOGE("failed to link elements");
3822 /* get first element's sinkpad for creating ghostpad */
3823 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3824 if (!first_element) {
3825 LOGE("failed to get first element from bucket");
3829 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3831 LOGE("failed to get pad from first element");
3835 /* create ghostpad */
3836 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3837 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3838 LOGE("failed to add ghostpad to videobin");
3841 gst_object_unref(pad);
3843 /* done. free allocated variables */
3844 g_list_free(element_bucket);
3848 return MM_ERROR_NONE;
3851 LOGE("ERROR : releasing videobin");
3852 g_list_free(element_bucket);
3855 gst_object_unref(GST_OBJECT(pad));
3857 /* release videobin with it's children */
3858 if (videobin[MMPLAYER_V_BIN].gst)
3859 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3861 MMPLAYER_FREEIF(videobin);
3862 player->pipeline->videobin = NULL;
3864 return MM_ERROR_PLAYER_INTERNAL;
3868 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3870 GList *element_bucket = NULL;
3871 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3873 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3874 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3875 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3876 "signal-handoffs", FALSE,
3879 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3880 _mmplayer_add_signal_connection(player,
3881 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3882 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3884 G_CALLBACK(__mmplayer_update_subtitle),
3887 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3888 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3890 if (!player->play_subtitle) {
3891 LOGD("add textbin sink as sink element of whole pipeline.");
3892 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3895 /* adding created elements to bin */
3896 LOGD("adding created elements to bin");
3897 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3898 LOGE("failed to add elements");
3902 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3903 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3904 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3906 /* linking elements in the bucket by added order. */
3907 LOGD("Linking elements in the bucket by added order.");
3908 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3909 LOGE("failed to link elements");
3913 if (textbin[MMPLAYER_T_QUEUE].gst) {
3915 GstPad *ghostpad = NULL;
3917 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3919 LOGE("failed to get sink pad of text queue");
3923 ghostpad = gst_ghost_pad_new("text_sink", pad);
3924 gst_object_unref(pad);
3927 LOGE("failed to create ghostpad of textbin");
3931 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3932 LOGE("failed to add ghostpad to textbin");
3933 gst_object_unref(ghostpad);
3938 g_list_free(element_bucket);
3940 return MM_ERROR_NONE;
3944 g_list_free(element_bucket);
3946 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3947 LOGE("remove textbin sink from sink list");
3948 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3951 /* release element at __mmplayer_gst_create_text_sink_bin */
3952 return MM_ERROR_PLAYER_INTERNAL;
3956 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3958 mmplayer_gst_element_t *textbin = NULL;
3959 int surface_type = 0;
3964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3967 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3969 LOGE("failed to allocate memory for textbin");
3970 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3974 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3975 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3976 if (!textbin[MMPLAYER_T_BIN].gst) {
3977 LOGE("failed to create textbin");
3982 player->pipeline->textbin = textbin;
3985 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3986 LOGD("surface type for subtitle : %d", surface_type);
3987 switch (surface_type) {
3988 case MM_DISPLAY_SURFACE_OVERLAY:
3989 case MM_DISPLAY_SURFACE_NULL:
3990 case MM_DISPLAY_SURFACE_REMOTE:
3991 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3992 LOGE("failed to make plain text elements");
4003 return MM_ERROR_NONE;
4007 LOGD("ERROR : releasing textbin");
4009 /* release signal */
4010 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4012 /* release element which are not added to bin */
4013 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4014 /* NOTE : skip bin */
4015 if (textbin[i].gst) {
4016 GstObject *parent = NULL;
4017 parent = gst_element_get_parent(textbin[i].gst);
4020 gst_object_unref(GST_OBJECT(textbin[i].gst));
4021 textbin[i].gst = NULL;
4023 gst_object_unref(GST_OBJECT(parent));
4028 /* release textbin with it's children */
4029 if (textbin[MMPLAYER_T_BIN].gst)
4030 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4032 MMPLAYER_FREEIF(textbin);
4033 player->pipeline->textbin = NULL;
4036 return MM_ERROR_PLAYER_INTERNAL;
4040 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4042 mmplayer_gst_element_t *mainbin = NULL;
4043 mmplayer_gst_element_t *textbin = NULL;
4044 MMHandleType attrs = 0;
4045 GstElement *subsrc = NULL;
4046 GstElement *subparse = NULL;
4047 gchar *subtitle_uri = NULL;
4048 const gchar *charset = NULL;
4054 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4056 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4058 mainbin = player->pipeline->mainbin;
4060 attrs = MMPLAYER_GET_ATTRS(player);
4062 LOGE("cannot get content attribute");
4063 return MM_ERROR_PLAYER_INTERNAL;
4066 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4067 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4068 LOGE("subtitle uri is not proper filepath.");
4069 return MM_ERROR_PLAYER_INVALID_URI;
4072 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4073 LOGE("failed to get storage info of subtitle path");
4074 return MM_ERROR_PLAYER_INVALID_URI;
4077 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4079 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4080 player->subtitle_language_list = NULL;
4081 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4083 /* create the subtitle source */
4084 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4086 LOGE("failed to create filesrc element");
4089 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4091 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4092 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4094 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4095 LOGW("failed to add queue");
4096 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4097 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4098 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4103 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4105 LOGE("failed to create subparse element");
4109 charset = _mmplayer_get_charset(subtitle_uri);
4111 LOGD("detected charset is %s", charset);
4112 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4115 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4116 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4118 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4119 LOGW("failed to add subparse");
4120 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4121 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4122 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4126 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4127 LOGW("failed to link subsrc and subparse");
4131 player->play_subtitle = TRUE;
4132 player->adjust_subtitle_pos = 0;
4134 LOGD("play subtitle using subtitle file");
4136 if (player->pipeline->textbin == NULL) {
4137 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4138 LOGE("failed to create text sink bin. continuing without text");
4142 textbin = player->pipeline->textbin;
4144 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4145 LOGW("failed to add textbin");
4147 /* release signal */
4148 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4150 /* release textbin with it's children */
4151 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4152 MMPLAYER_FREEIF(player->pipeline->textbin);
4153 player->pipeline->textbin = textbin = NULL;
4157 LOGD("link text input selector and textbin ghost pad");
4159 player->textsink_linked = 1;
4160 player->external_text_idx = 0;
4161 LOGI("textsink is linked");
4163 textbin = player->pipeline->textbin;
4164 LOGD("text bin has been created. reuse it.");
4165 player->external_text_idx = 1;
4168 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4169 LOGW("failed to link subparse and textbin");
4173 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4175 LOGE("failed to get sink pad from textsink to probe data");
4179 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4180 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4182 gst_object_unref(pad);
4185 /* create dot. for debugging */
4186 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4189 return MM_ERROR_NONE;
4192 /* release text pipeline resource */
4193 player->textsink_linked = 0;
4195 /* release signal */
4196 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4198 if (player->pipeline->textbin) {
4199 LOGE("remove textbin");
4201 /* release textbin with it's children */
4202 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4203 MMPLAYER_FREEIF(player->pipeline->textbin);
4204 player->pipeline->textbin = NULL;
4208 /* release subtitle elem */
4209 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4210 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4212 return MM_ERROR_PLAYER_INTERNAL;
4216 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4218 mmplayer_t *player = (mmplayer_t *)data;
4219 MMMessageParamType msg = {0, };
4220 GstClockTime duration = 0;
4221 gpointer text = NULL;
4222 guint text_size = 0;
4223 gboolean ret = TRUE;
4224 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4228 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4229 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4231 if (player->is_subtitle_force_drop) {
4232 LOGW("subtitle is dropped forcedly.");
4236 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4237 text = mapinfo.data;
4238 text_size = mapinfo.size;
4240 if (player->set_mode.subtitle_off) {
4241 LOGD("subtitle is OFF.");
4245 if (!text || (text_size == 0)) {
4246 LOGD("There is no subtitle to be displayed.");
4250 msg.data = (void *)text;
4252 duration = GST_BUFFER_DURATION(buffer);
4254 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4255 if (player->duration > GST_BUFFER_PTS(buffer))
4256 duration = player->duration - GST_BUFFER_PTS(buffer);
4259 LOGI("subtitle duration is invalid, subtitle duration change "
4260 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4262 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4264 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4266 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4267 gst_buffer_unmap(buffer, &mapinfo);
4274 static GstPadProbeReturn
4275 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4277 mmplayer_t *player = (mmplayer_t *)u_data;
4278 GstClockTime cur_timestamp = 0;
4279 gint64 adjusted_timestamp = 0;
4280 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4282 MMPLAYER_RETURN_VAL_IF_FAIL(player, GST_PAD_PROBE_DROP);
4284 if (player->set_mode.subtitle_off)
4285 return GST_PAD_PROBE_OK;
4287 if (player->adjust_subtitle_pos == 0)
4288 return GST_PAD_PROBE_OK;
4290 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4291 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4293 if (adjusted_timestamp < 0) {
4294 LOGD("adjusted_timestamp under zero");
4296 return GST_PAD_PROBE_DROP;
4299 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4300 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4301 GST_TIME_ARGS(cur_timestamp),
4302 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4304 return GST_PAD_PROBE_OK;
4308 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4312 /* check player and subtitlebin are created */
4313 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4314 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4316 if (position == 0) {
4317 LOGD("nothing to do");
4319 return MM_ERROR_NONE;
4322 /* check current position */
4323 player->adjust_subtitle_pos = position;
4325 LOGD("save adjust_subtitle_pos in player");
4329 return MM_ERROR_NONE;
4333 * This function is to create audio or video pipeline for playing.
4335 * @param player [in] handle of player
4337 * @return This function returns zero on success.
4342 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4344 int ret = MM_ERROR_NONE;
4345 mmplayer_gst_element_t *mainbin = NULL;
4346 MMHandleType attrs = 0;
4349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4351 /* get profile attribute */
4352 attrs = MMPLAYER_GET_ATTRS(player);
4354 LOGE("failed to get content attribute");
4358 /* create pipeline handles */
4359 if (player->pipeline) {
4360 LOGE("pipeline should be released before create new one");
4364 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4366 /* create mainbin */
4367 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4368 if (mainbin == NULL)
4371 /* create pipeline */
4372 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4373 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4374 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4375 LOGE("failed to create pipeline");
4380 player->pipeline->mainbin = mainbin;
4382 /* create the source and decoder elements */
4383 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4384 ret = _mmplayer_gst_build_es_pipeline(player);
4386 if (MMPLAYER_USE_DECODEBIN(player))
4387 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4389 ret = _mmplayer_gst_build_pipeline_with_src(player);
4392 if (ret != MM_ERROR_NONE) {
4393 LOGE("failed to create some elements");
4397 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4398 if (__mmplayer_check_subtitle(player)
4399 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4400 LOGE("failed to create text pipeline");
4403 ret = _mmplayer_gst_add_bus_watch(player);
4404 if (ret != MM_ERROR_NONE) {
4405 LOGE("failed to add bus watch");
4410 return MM_ERROR_NONE;
4413 _mmplayer_bus_watcher_remove(player);
4414 __mmplayer_gst_destroy_pipeline(player);
4415 return MM_ERROR_PLAYER_INTERNAL;
4419 __mmplayer_reset_gapless_state(mmplayer_t *player)
4422 MMPLAYER_RETURN_IF_FAIL(player
4424 && player->pipeline->audiobin
4425 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4427 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4434 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4437 int ret = MM_ERROR_NONE;
4441 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4443 /* cleanup stuffs */
4444 MMPLAYER_FREEIF(player->type_caps_str);
4445 player->no_more_pad = FALSE;
4446 player->num_dynamic_pad = 0;
4448 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4449 player->subtitle_language_list = NULL;
4450 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4452 MMPLAYER_RECONFIGURE_LOCK(player);
4453 __mmplayer_reset_gapless_state(player);
4454 MMPLAYER_RECONFIGURE_UNLOCK(player);
4456 if (player->streamer) {
4457 _mm_player_streaming_initialize(player->streamer, FALSE);
4458 _mm_player_streaming_destroy(player->streamer);
4459 player->streamer = NULL;
4462 /* cleanup unlinked mime type */
4463 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4464 MMPLAYER_FREEIF(player->unlinked_video_mime);
4465 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4467 /* cleanup running stuffs */
4468 _mmplayer_cancel_eos_timer(player);
4470 /* cleanup gst stuffs */
4471 if (player->pipeline) {
4472 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4473 GstTagList *tag_list = player->pipeline->tag_list;
4475 /* first we need to disconnect all signal hander */
4476 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4479 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4480 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4481 gst_object_unref(bus);
4483 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4484 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4485 if (ret != MM_ERROR_NONE) {
4486 LOGE("fail to change state to NULL");
4487 return MM_ERROR_PLAYER_INTERNAL;
4490 LOGW("succeeded in changing state to NULL");
4492 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4495 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4496 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4498 MMPLAYER_FREEIF(player->pipeline->audiobin);
4499 MMPLAYER_FREEIF(player->pipeline->videobin);
4500 MMPLAYER_FREEIF(player->pipeline->textbin);
4501 MMPLAYER_FREEIF(mainbin);
4505 gst_tag_list_unref(tag_list);
4507 MMPLAYER_FREEIF(player->pipeline);
4509 MMPLAYER_FREEIF(player->album_art);
4511 if (player->v_stream_caps) {
4512 gst_caps_unref(player->v_stream_caps);
4513 player->v_stream_caps = NULL;
4516 if (player->a_stream_caps) {
4517 gst_caps_unref(player->a_stream_caps);
4518 player->a_stream_caps = NULL;
4521 if (player->s_stream_caps) {
4522 gst_caps_unref(player->s_stream_caps);
4523 player->s_stream_caps = NULL;
4525 _mmplayer_track_destroy(player);
4527 if (player->sink_elements)
4528 g_list_free(player->sink_elements);
4529 player->sink_elements = NULL;
4531 if (player->bufmgr) {
4532 tbm_bufmgr_deinit(player->bufmgr);
4533 player->bufmgr = NULL;
4536 LOGW("finished destroy pipeline");
4544 __mmplayer_gst_realize(mmplayer_t *player)
4547 int ret = MM_ERROR_NONE;
4551 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4553 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4555 ret = __mmplayer_gst_create_pipeline(player);
4557 LOGE("failed to create pipeline");
4561 /* set pipeline state to READY */
4562 /* NOTE : state change to READY must be performed sync. */
4563 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4564 ret = _mmplayer_gst_set_state(player,
4565 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4567 if (ret != MM_ERROR_NONE) {
4568 /* return error if failed to set state */
4569 LOGE("failed to set READY state");
4573 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4575 /* create dot before error-return. for debugging */
4576 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4584 __mmplayer_gst_unrealize(mmplayer_t *player)
4586 int ret = MM_ERROR_NONE;
4590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4592 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4593 MMPLAYER_PRINT_STATE(player);
4595 /* release miscellaneous information */
4596 __mmplayer_release_misc(player);
4598 /* destroy pipeline */
4599 ret = __mmplayer_gst_destroy_pipeline(player);
4600 if (ret != MM_ERROR_NONE) {
4601 LOGE("failed to destroy pipeline");
4605 /* release miscellaneous information.
4606 these info needs to be released after pipeline is destroyed. */
4607 __mmplayer_release_misc_post(player);
4609 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4617 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4622 LOGW("set_message_callback is called with invalid player handle");
4623 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4626 player->msg_cb = callback;
4627 player->msg_cb_param = user_param;
4629 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4633 return MM_ERROR_NONE;
4637 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4639 int ret = MM_ERROR_NONE;
4644 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4645 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4646 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4648 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4650 if (strstr(uri, "es_buff://")) {
4651 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4652 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4653 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4654 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4656 tmp = g_ascii_strdown(uri, strlen(uri));
4657 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4658 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4660 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4662 } else if (strstr(uri, "mms://")) {
4663 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4664 } else if ((path = strstr(uri, "mem://"))) {
4665 ret = __mmplayer_set_mem_uri(data, path, param);
4667 ret = __mmplayer_set_file_uri(data, uri);
4670 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4671 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4672 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4673 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4675 /* dump parse result */
4676 SECURE_LOGW("incoming uri : %s", uri);
4677 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4678 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4686 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4689 mmplayer_t *player = NULL;
4690 MMMessageParamType msg = {0, };
4692 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4697 LOGE("user_data is null");
4701 player = (mmplayer_t *)user_data;
4703 if (!player->pipeline || !player->attrs) {
4704 LOGW("not initialized");
4708 LOGD("cmd lock player, cmd state : %d", player->cmd);
4709 MMPLAYER_CMD_LOCK(player);
4710 LOGD("cmd locked player");
4712 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4713 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4714 LOGW("player already destroyed");
4715 MMPLAYER_CMD_UNLOCK(player);
4719 player->interrupted_by_resource = TRUE;
4721 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4723 /* get last play position */
4724 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4725 msg.union_type = MM_MSG_UNION_TIME;
4726 msg.time.elapsed = pos;
4727 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4729 LOGW("failed to get play position.");
4732 LOGD("video resource conflict so, resource will be freed by unrealizing");
4733 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4734 LOGE("failed to unrealize");
4736 MMPLAYER_CMD_UNLOCK(player);
4738 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4739 player->hw_resource[res_idx] = NULL;
4743 return TRUE; /* release all the resources */
4747 __mmplayer_initialize_video_roi(mmplayer_t *player)
4749 player->video_roi.scale_x = 0.0;
4750 player->video_roi.scale_y = 0.0;
4751 player->video_roi.scale_width = 1.0;
4752 player->video_roi.scale_height = 1.0;
4756 _mmplayer_create_player(MMHandleType handle)
4758 int ret = MM_ERROR_PLAYER_INTERNAL;
4759 bool enabled = false;
4761 mmplayer_t *player = MM_PLAYER_CAST(handle);
4765 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4767 /* initialize player state */
4768 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4769 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4770 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4771 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4773 /* check current state */
4774 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4776 /* construct attributes */
4777 player->attrs = _mmplayer_construct_attribute(handle);
4779 if (!player->attrs) {
4780 LOGE("Failed to construct attributes");
4784 /* initialize gstreamer with configured parameter */
4785 if (!__mmplayer_init_gstreamer(player)) {
4786 LOGE("Initializing gstreamer failed");
4787 _mmplayer_deconstruct_attribute(handle);
4791 /* create lock. note that g_tread_init() has already called in gst_init() */
4792 g_mutex_init(&player->fsink_lock);
4794 /* create update tag lock */
4795 g_mutex_init(&player->update_tag_lock);
4797 /* create gapless play mutex */
4798 g_mutex_init(&player->gapless_play_thread_mutex);
4800 /* create gapless play cond */
4801 g_cond_init(&player->gapless_play_thread_cond);
4803 /* create gapless play thread */
4804 player->gapless_play_thread =
4805 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4806 if (!player->gapless_play_thread) {
4807 LOGE("failed to create gapless play thread");
4808 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4809 g_mutex_clear(&player->gapless_play_thread_mutex);
4810 g_cond_clear(&player->gapless_play_thread_cond);
4814 player->bus_msg_q = g_queue_new();
4815 if (!player->bus_msg_q) {
4816 LOGE("failed to create queue for bus_msg");
4817 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4821 ret = _mmplayer_initialize_video_capture(player);
4822 if (ret != MM_ERROR_NONE) {
4823 LOGW("video capture is not supported");
4824 /* do not handle as error for headless profile */
4827 /* initialize resource manager */
4828 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4829 __resource_release_cb, player, &player->resource_manager)
4830 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4831 LOGE("failed to create resource manager");
4832 ret = MM_ERROR_PLAYER_INTERNAL;
4836 /* create video bo lock and cond */
4837 g_mutex_init(&player->video_bo_mutex);
4838 g_cond_init(&player->video_bo_cond);
4840 /* create subtitle info lock and cond */
4841 g_mutex_init(&player->subtitle_info_mutex);
4842 g_cond_init(&player->subtitle_info_cond);
4844 player->streaming_type = STREAMING_SERVICE_NONE;
4846 /* give default value of audio effect setting */
4847 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4848 player->sound.rg_enable = false;
4849 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4851 player->play_subtitle = FALSE;
4852 player->has_closed_caption = FALSE;
4853 player->pending_resume = FALSE;
4854 if (player->ini.dump_element_keyword[0][0] == '\0')
4855 player->ini.set_dump_element_flag = FALSE;
4857 player->ini.set_dump_element_flag = TRUE;
4859 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4860 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4861 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4863 /* Set video360 settings to their defaults for just-created player.
4866 player->is_360_feature_enabled = FALSE;
4867 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4868 LOGI("spherical feature info: %d", enabled);
4870 player->is_360_feature_enabled = TRUE;
4872 LOGE("failed to get spherical feature info");
4875 player->is_content_spherical = FALSE;
4876 player->is_video360_enabled = TRUE;
4877 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4878 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4879 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4880 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4881 player->video360_zoom = 1.0f;
4882 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4883 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4885 __mmplayer_initialize_video_roi(player);
4887 /* set player state to null */
4888 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4889 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4893 return MM_ERROR_NONE;
4897 g_mutex_clear(&player->fsink_lock);
4898 /* free update tag lock */
4899 g_mutex_clear(&player->update_tag_lock);
4900 g_queue_free(player->bus_msg_q);
4901 player->bus_msg_q = NULL;
4902 /* free gapless play thread */
4903 if (player->gapless_play_thread) {
4904 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4905 player->gapless_play_thread_exit = TRUE;
4906 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4907 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4909 g_thread_join(player->gapless_play_thread);
4910 player->gapless_play_thread = NULL;
4912 g_mutex_clear(&player->gapless_play_thread_mutex);
4913 g_cond_clear(&player->gapless_play_thread_cond);
4916 /* release attributes */
4917 _mmplayer_deconstruct_attribute(handle);
4925 __mmplayer_init_gstreamer(mmplayer_t *player)
4927 static gboolean initialized = FALSE;
4928 static const int max_argc = 50;
4930 gchar **argv = NULL;
4931 gchar **argv2 = NULL;
4937 LOGD("gstreamer already initialized.");
4942 argc = malloc(sizeof(int));
4943 argv = malloc(sizeof(gchar *) * max_argc);
4944 argv2 = malloc(sizeof(gchar *) * max_argc);
4946 if (!argc || !argv || !argv2)
4949 memset(argv, 0, sizeof(gchar *) * max_argc);
4950 memset(argv2, 0, sizeof(gchar *) * max_argc);
4954 argv[0] = g_strdup("mmplayer");
4957 for (i = 0; i < 5; i++) {
4958 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4959 if (strlen(player->ini.gst_param[i]) > 0) {
4960 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4965 /* we would not do fork for scanning plugins */
4966 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4969 /* check disable registry scan */
4970 if (player->ini.skip_rescan) {
4971 argv[*argc] = g_strdup("--gst-disable-registry-update");
4975 /* check disable segtrap */
4976 if (player->ini.disable_segtrap) {
4977 argv[*argc] = g_strdup("--gst-disable-segtrap");
4981 LOGD("initializing gstreamer with following parameter");
4982 LOGD("argc : %d", *argc);
4985 for (i = 0; i < arg_count; i++) {
4987 LOGD("argv[%d] : %s", i, argv2[i]);
4990 /* initializing gstreamer */
4991 if (!gst_init_check(argc, &argv, &err)) {
4992 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4999 for (i = 0; i < arg_count; i++) {
5001 LOGD("release - argv[%d] : %s", i, argv2[i]);
5003 MMPLAYER_FREEIF(argv2[i]);
5006 MMPLAYER_FREEIF(argv);
5007 MMPLAYER_FREEIF(argv2);
5008 MMPLAYER_FREEIF(argc);
5018 for (i = 0; i < arg_count; i++) {
5019 LOGD("free[%d] : %s", i, argv2[i]);
5020 MMPLAYER_FREEIF(argv2[i]);
5023 MMPLAYER_FREEIF(argv);
5024 MMPLAYER_FREEIF(argv2);
5025 MMPLAYER_FREEIF(argc);
5031 __mmplayer_check_async_state_transition(mmplayer_t *player)
5033 GstState element_state = GST_STATE_VOID_PENDING;
5034 GstState element_pending_state = GST_STATE_VOID_PENDING;
5035 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5036 GstElement *element = NULL;
5037 gboolean async = FALSE;
5039 /* check player handle */
5040 MMPLAYER_RETURN_IF_FAIL(player &&
5042 player->pipeline->mainbin &&
5043 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5046 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5048 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5049 LOGD("don't need to check the pipeline state");
5053 MMPLAYER_PRINT_STATE(player);
5055 /* wait for state transition */
5056 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5057 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5059 if (ret == GST_STATE_CHANGE_FAILURE) {
5060 LOGE(" [%s] state : %s pending : %s",
5061 GST_ELEMENT_NAME(element),
5062 gst_element_state_get_name(element_state),
5063 gst_element_state_get_name(element_pending_state));
5065 /* dump state of all element */
5066 _mmplayer_dump_pipeline_state(player);
5071 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5076 _mmplayer_destroy(MMHandleType handle)
5078 mmplayer_t *player = MM_PLAYER_CAST(handle);
5082 /* check player handle */
5083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5085 /* destroy can called at anytime */
5086 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5088 /* check async state transition */
5089 __mmplayer_check_async_state_transition(player);
5091 /* release gapless play thread */
5092 if (player->gapless_play_thread) {
5093 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5094 player->gapless_play_thread_exit = TRUE;
5095 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5096 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5098 LOGD("waiting for gapless play thread exit");
5099 g_thread_join(player->gapless_play_thread);
5100 g_mutex_clear(&player->gapless_play_thread_mutex);
5101 g_cond_clear(&player->gapless_play_thread_cond);
5102 LOGD("gapless play thread released");
5105 _mmplayer_release_video_capture(player);
5107 /* release miscellaneous information */
5108 __mmplayer_release_misc(player);
5110 /* release pipeline */
5111 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5112 LOGE("failed to destroy pipeline");
5113 return MM_ERROR_PLAYER_INTERNAL;
5116 __mmplayer_destroy_hw_resource(player);
5118 g_queue_free(player->bus_msg_q);
5120 /* release subtitle info lock and cond */
5121 g_mutex_clear(&player->subtitle_info_mutex);
5122 g_cond_clear(&player->subtitle_info_cond);
5124 __mmplayer_release_dump_list(player->dump_list);
5126 /* release miscellaneous information.
5127 these info needs to be released after pipeline is destroyed. */
5128 __mmplayer_release_misc_post(player);
5130 /* release attributes */
5131 _mmplayer_deconstruct_attribute(handle);
5133 if (player->uri_info.uri_list) {
5134 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5135 player->uri_info.uri_list = NULL;
5139 g_mutex_clear(&player->fsink_lock);
5142 g_mutex_clear(&player->update_tag_lock);
5144 /* release video bo lock and cond */
5145 g_mutex_clear(&player->video_bo_mutex);
5146 g_cond_clear(&player->video_bo_cond);
5150 return MM_ERROR_NONE;
5154 _mmplayer_realize(MMHandleType hplayer)
5156 mmplayer_t *player = (mmplayer_t *)hplayer;
5157 int ret = MM_ERROR_NONE;
5160 MMHandleType attrs = 0;
5164 /* check player handle */
5165 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5167 /* check current state */
5168 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5170 attrs = MMPLAYER_GET_ATTRS(player);
5172 LOGE("fail to get attributes.");
5173 return MM_ERROR_PLAYER_INTERNAL;
5175 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5176 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5178 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5179 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5181 if (ret != MM_ERROR_NONE) {
5182 LOGE("failed to parse profile");
5187 if (uri && (strstr(uri, "es_buff://"))) {
5188 if (strstr(uri, "es_buff://push_mode"))
5189 player->es_player_push_mode = TRUE;
5191 player->es_player_push_mode = FALSE;
5194 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5195 LOGW("mms protocol is not supported format.");
5196 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5199 if (MMPLAYER_IS_STREAMING(player))
5200 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5202 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5204 player->smooth_streaming = FALSE;
5205 player->videodec_linked = 0;
5206 player->audiodec_linked = 0;
5207 player->textsink_linked = 0;
5208 player->is_external_subtitle_present = FALSE;
5209 player->is_external_subtitle_added_now = FALSE;
5210 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5211 player->video360_metadata.is_spherical = -1;
5212 player->is_openal_plugin_used = FALSE;
5213 player->subtitle_language_list = NULL;
5214 player->is_subtitle_force_drop = FALSE;
5216 _mmplayer_track_initialize(player);
5217 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5219 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5220 gint prebuffer_ms = 0, rebuffer_ms = 0;
5222 player->streamer = _mm_player_streaming_create();
5223 _mm_player_streaming_initialize(player->streamer, TRUE);
5225 mm_attrs_multiple_get(player->attrs, NULL,
5226 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5227 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5229 if (prebuffer_ms > 0) {
5230 prebuffer_ms = MAX(prebuffer_ms, 1000);
5231 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5234 if (rebuffer_ms > 0) {
5235 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5236 rebuffer_ms = MAX(rebuffer_ms, 1000);
5237 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5240 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5241 player->streamer->buffering_req.rebuffer_time);
5244 /* realize pipeline */
5245 ret = __mmplayer_gst_realize(player);
5246 if (ret != MM_ERROR_NONE)
5247 LOGE("fail to realize the player.");
5249 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5257 _mmplayer_unrealize(MMHandleType hplayer)
5259 mmplayer_t *player = (mmplayer_t *)hplayer;
5260 int ret = MM_ERROR_NONE;
5261 int rm_ret = MM_ERROR_NONE;
5262 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268 MMPLAYER_CMD_UNLOCK(player);
5269 _mmplayer_bus_watcher_remove(player);
5270 /* destroy the gst bus msg thread which is created during realize.
5271 this funct have to be called before getting cmd lock. */
5272 _mmplayer_bus_msg_thread_destroy(player);
5273 MMPLAYER_CMD_LOCK(player);
5275 /* check current state */
5276 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5278 /* check async state transition */
5279 __mmplayer_check_async_state_transition(player);
5281 /* unrealize pipeline */
5282 ret = __mmplayer_gst_unrealize(player);
5284 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5285 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5286 if (rm_ret != MM_ERROR_NONE)
5287 LOGE("failed to release [%d] resources", res_idx);
5290 player->interrupted_by_resource = FALSE;
5297 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5299 mmplayer_t *player = (mmplayer_t *)hplayer;
5301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5303 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5307 _mmplayer_get_state(MMHandleType hplayer, int *state)
5309 mmplayer_t *player = (mmplayer_t *)hplayer;
5311 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5313 *state = MMPLAYER_CURRENT_STATE(player);
5315 return MM_ERROR_NONE;
5319 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5321 GstElement *vol_element = NULL;
5322 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5326 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5328 /* check pipeline handle */
5329 if (!player->pipeline || !player->pipeline->audiobin) {
5330 LOGD("'%s' will be applied when audiobin is created", prop_name);
5332 /* NOTE : stored value will be used in create_audiobin
5333 * returning MM_ERROR_NONE here makes application to able to
5334 * set audio volume or mute at anytime.
5336 return MM_ERROR_NONE;
5339 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5340 volume_elem_id = MMPLAYER_A_SINK;
5342 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5344 LOGE("failed to get vol element %d", volume_elem_id);
5345 return MM_ERROR_PLAYER_INTERNAL;
5348 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5350 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5351 LOGE("there is no '%s' property", prop_name);
5352 return MM_ERROR_PLAYER_INTERNAL;
5355 if (!strcmp(prop_name, "volume")) {
5356 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5357 } else if (!strcmp(prop_name, "mute")) {
5358 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5360 LOGE("invalid property %s", prop_name);
5361 return MM_ERROR_PLAYER_INTERNAL;
5364 return MM_ERROR_NONE;
5368 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5370 int ret = MM_ERROR_NONE;
5371 mmplayer_t *player = (mmplayer_t *)hplayer;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 LOGD("volume = %f", volume);
5378 /* invalid factor range or not */
5379 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5380 LOGE("Invalid volume value");
5381 return MM_ERROR_INVALID_ARGUMENT;
5384 player->sound.volume = volume;
5386 ret = __mmplayer_gst_set_volume_property(player, "volume");
5393 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5395 mmplayer_t *player = (mmplayer_t *)hplayer;
5399 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5400 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5402 *volume = player->sound.volume;
5404 LOGD("current vol = %f", *volume);
5407 return MM_ERROR_NONE;
5411 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5413 int ret = MM_ERROR_NONE;
5414 mmplayer_t *player = (mmplayer_t *)hplayer;
5417 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5419 LOGD("mute = %d", mute);
5421 player->sound.mute = mute;
5423 ret = __mmplayer_gst_set_volume_property(player, "mute");
5430 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5432 mmplayer_t *player = (mmplayer_t *)hplayer;
5436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5437 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5439 *mute = player->sound.mute;
5441 LOGD("current mute = %d", *mute);
5445 return MM_ERROR_NONE;
5449 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5451 mmplayer_t *player = (mmplayer_t *)hplayer;
5455 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5457 player->audio_stream_changed_cb = callback;
5458 player->audio_stream_changed_cb_user_param = user_param;
5459 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5463 return MM_ERROR_NONE;
5467 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5469 mmplayer_t *player = (mmplayer_t *)hplayer;
5473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5475 player->audio_decoded_cb = callback;
5476 player->audio_decoded_cb_user_param = user_param;
5477 player->audio_extract_opt = opt;
5478 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5482 return MM_ERROR_NONE;
5486 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5488 mmplayer_t *player = (mmplayer_t *)hplayer;
5492 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5494 if (callback && !player->bufmgr)
5495 player->bufmgr = tbm_bufmgr_init(-1);
5497 player->set_mode.video_export = (callback) ? true : false;
5498 player->video_decoded_cb = callback;
5499 player->video_decoded_cb_user_param = user_param;
5501 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5505 return MM_ERROR_NONE;
5509 _mmplayer_start(MMHandleType hplayer)
5511 mmplayer_t *player = (mmplayer_t *)hplayer;
5512 gint ret = MM_ERROR_NONE;
5516 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5518 /* check current state */
5519 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5521 /* start pipeline */
5522 ret = _mmplayer_gst_start(player);
5523 if (ret != MM_ERROR_NONE)
5524 LOGE("failed to start player.");
5526 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5527 LOGD("force playing start even during buffering");
5528 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5536 /* NOTE: post "not supported codec message" to application
5537 * when one codec is not found during AUTOPLUGGING in MSL.
5538 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5539 * And, if any codec is not found, don't send message here.
5540 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5543 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5545 MMMessageParamType msg_param;
5546 memset(&msg_param, 0, sizeof(MMMessageParamType));
5547 gboolean post_msg_direct = FALSE;
5551 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5553 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5554 player->not_supported_codec, player->can_support_codec);
5556 if (player->not_found_demuxer) {
5557 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5558 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5560 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5561 MMPLAYER_FREEIF(msg_param.data);
5563 return MM_ERROR_NONE;
5566 if (player->not_supported_codec) {
5567 if (player->can_support_codec) {
5568 // There is one codec to play
5569 post_msg_direct = TRUE;
5571 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5572 post_msg_direct = TRUE;
5575 if (post_msg_direct) {
5576 MMMessageParamType msg_param;
5577 memset(&msg_param, 0, sizeof(MMMessageParamType));
5579 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5580 LOGW("not found AUDIO codec, posting error code to application.");
5582 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5583 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5584 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5585 LOGW("not found VIDEO codec, posting error code to application.");
5587 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5588 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5591 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5593 MMPLAYER_FREEIF(msg_param.data);
5595 return MM_ERROR_NONE;
5597 // no any supported codec case
5598 LOGW("not found any codec, posting error code to application.");
5600 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5601 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5602 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5604 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5605 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5608 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5610 MMPLAYER_FREEIF(msg_param.data);
5616 return MM_ERROR_NONE;
5619 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5621 GstState element_state = GST_STATE_VOID_PENDING;
5622 GstState element_pending_state = GST_STATE_VOID_PENDING;
5623 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5624 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5626 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5628 MMPLAYER_RECONFIGURE_LOCK(player);
5629 if (!player->gapless.reconfigure) {
5630 MMPLAYER_RECONFIGURE_UNLOCK(player);
5634 LOGI("reconfigure is under process");
5635 MMPLAYER_RECONFIGURE_WAIT(player);
5636 MMPLAYER_RECONFIGURE_UNLOCK(player);
5637 LOGI("reconfigure is completed.");
5639 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5640 &element_state, &element_pending_state, timeout * GST_SECOND);
5641 if (result == GST_STATE_CHANGE_FAILURE)
5642 LOGW("failed to get pipeline state in %d sec", timeout);
5647 /* NOTE : it should be able to call 'stop' anytime*/
5649 _mmplayer_stop(MMHandleType hplayer)
5651 mmplayer_t *player = (mmplayer_t *)hplayer;
5652 int ret = MM_ERROR_NONE;
5656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5658 /* check current state */
5659 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5661 /* need to wait till the rebuilding pipeline is completed */
5662 __mmplayer_check_pipeline_reconfigure_state(player);
5663 MMPLAYER_RECONFIGURE_LOCK(player);
5664 __mmplayer_reset_gapless_state(player);
5665 MMPLAYER_RECONFIGURE_UNLOCK(player);
5667 /* NOTE : application should not wait for EOS after calling STOP */
5668 _mmplayer_cancel_eos_timer(player);
5671 player->seek_state = MMPLAYER_SEEK_NONE;
5674 ret = _mmplayer_gst_stop(player);
5676 if (ret != MM_ERROR_NONE)
5677 LOGE("failed to stop player.");
5685 _mmplayer_pause(MMHandleType hplayer)
5687 mmplayer_t *player = (mmplayer_t *)hplayer;
5688 gint64 pos_nsec = 0;
5689 gboolean async = FALSE;
5690 gint ret = MM_ERROR_NONE;
5694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5696 /* check current state */
5697 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5699 /* check pipeline reconfigure state */
5700 __mmplayer_check_pipeline_reconfigure_state(player);
5702 switch (MMPLAYER_CURRENT_STATE(player)) {
5703 case MM_PLAYER_STATE_READY:
5705 /* check prepare async or not.
5706 * In the case of streaming playback, it's recommended to avoid blocking wait.
5708 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5709 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5711 /* Changing back sync of rtspsrc to async */
5712 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5713 LOGD("async prepare working mode for rtsp");
5719 case MM_PLAYER_STATE_PLAYING:
5721 /* NOTE : store current point to overcome some bad operation
5722 *(returning zero when getting current position in paused state) of some
5725 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5726 LOGW("getting current position failed in paused");
5728 player->last_position = pos_nsec;
5730 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5731 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5732 This causes problem is position calculation during normal pause resume scenarios also.
5733 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5734 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5735 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5736 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5742 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5743 LOGD("doing async pause in case of ms buff src");
5747 /* pause pipeline */
5748 ret = _mmplayer_gst_pause(player, async);
5749 if (ret != MM_ERROR_NONE) {
5750 LOGE("failed to pause player. ret : 0x%x", ret);
5751 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5755 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5756 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5757 LOGE("failed to update display_rotation");
5761 return MM_ERROR_NONE;
5764 /* in case of streaming, pause could take long time.*/
5766 _mmplayer_abort_pause(MMHandleType hplayer)
5768 mmplayer_t *player = (mmplayer_t *)hplayer;
5769 int ret = MM_ERROR_NONE;
5773 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5775 player->pipeline->mainbin,
5776 MM_ERROR_PLAYER_NOT_INITIALIZED);
5778 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5779 LOGD("set the videobin state to READY");
5780 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5781 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5785 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5786 LOGD("set the audiobin state to READY");
5787 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5788 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5792 LOGD("set the pipeline state to READY");
5793 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5794 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5796 if (ret != MM_ERROR_NONE) {
5797 LOGE("fail to change state to READY");
5798 return MM_ERROR_PLAYER_INTERNAL;
5801 LOGD("succeeded in changing state to READY");
5806 _mmplayer_resume(MMHandleType hplayer)
5808 mmplayer_t *player = (mmplayer_t *)hplayer;
5809 int ret = MM_ERROR_NONE;
5810 gboolean async = FALSE;
5814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5816 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5817 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5818 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5822 /* Changing back sync mode rtspsrc to async */
5823 LOGD("async resume for rtsp case");
5827 /* check current state */
5828 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5830 ret = _mmplayer_gst_resume(player, async);
5831 if (ret != MM_ERROR_NONE)
5832 LOGE("failed to resume player.");
5834 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5835 LOGD("force resume even during buffering");
5836 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5845 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5847 mmplayer_t *player = (mmplayer_t *)hplayer;
5848 gint64 pos_nsec = 0;
5849 int ret = MM_ERROR_NONE;
5851 signed long long start = 0, stop = 0;
5852 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5855 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5856 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5858 /* The sound of video is not supported under 0.0 and over 2.0. */
5859 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5860 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5863 _mmplayer_set_mute(hplayer, mute);
5865 if (player->playback_rate == rate)
5866 return MM_ERROR_NONE;
5868 /* If the position is reached at start potion during fast backward, EOS is posted.
5869 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5871 player->playback_rate = rate;
5873 current_state = MMPLAYER_CURRENT_STATE(player);
5875 if (current_state != MM_PLAYER_STATE_PAUSED)
5876 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5878 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5880 if ((current_state == MM_PLAYER_STATE_PAUSED)
5881 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5882 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5883 pos_nsec = player->last_position;
5888 stop = GST_CLOCK_TIME_NONE;
5890 start = GST_CLOCK_TIME_NONE;
5894 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5895 player->playback_rate,
5897 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5898 GST_SEEK_TYPE_SET, start,
5899 GST_SEEK_TYPE_SET, stop)) {
5900 LOGE("failed to set speed playback");
5901 return MM_ERROR_PLAYER_SEEK;
5904 LOGD("succeeded to set speed playback as %0.1f", rate);
5908 return MM_ERROR_NONE;;
5912 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5914 mmplayer_t *player = (mmplayer_t *)hplayer;
5915 int ret = MM_ERROR_NONE;
5919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5921 /* check pipeline reconfigure state */
5922 __mmplayer_check_pipeline_reconfigure_state(player);
5924 ret = _mmplayer_gst_set_position(player, position, FALSE);
5932 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5934 mmplayer_t *player = (mmplayer_t *)hplayer;
5935 int ret = MM_ERROR_NONE;
5937 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5938 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5940 if (g_strrstr(player->type_caps_str, "video/mpegts"))
5941 __mmplayer_update_duration_value(player);
5943 *duration = player->duration;
5948 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5950 mmplayer_t *player = (mmplayer_t *)hplayer;
5951 int ret = MM_ERROR_NONE;
5953 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5955 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5961 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5963 mmplayer_t *player = (mmplayer_t *)hplayer;
5964 int ret = MM_ERROR_NONE;
5968 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5970 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5978 __mmplayer_is_midi_type(gchar *str_caps)
5980 if ((g_strrstr(str_caps, "audio/midi")) ||
5981 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5982 (g_strrstr(str_caps, "application/x-smaf")) ||
5983 (g_strrstr(str_caps, "audio/x-imelody")) ||
5984 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5985 (g_strrstr(str_caps, "audio/xmf")) ||
5986 (g_strrstr(str_caps, "audio/mxmf"))) {
5995 __mmplayer_is_only_mp3_type(gchar *str_caps)
5997 if (g_strrstr(str_caps, "application/x-id3") ||
5998 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
6004 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
6006 GstStructure *caps_structure = NULL;
6007 gint samplerate = 0;
6011 MMPLAYER_RETURN_IF_FAIL(player && caps);
6013 caps_structure = gst_caps_get_structure(caps, 0);
6015 /* set stream information */
6016 gst_structure_get_int(caps_structure, "rate", &samplerate);
6017 gst_structure_get_int(caps_structure, "channels", &channels);
6019 mm_player_set_attribute((MMHandleType)player, NULL,
6020 "content_audio_samplerate", samplerate,
6021 "content_audio_channels", channels, NULL);
6023 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6027 __mmplayer_update_content_type_info(mmplayer_t *player)
6030 MMPLAYER_RETURN_IF_FAIL(player && player->type_caps_str);
6032 if (__mmplayer_is_midi_type(player->type_caps_str)) {
6033 player->bypass_audio_effect = TRUE;
6037 if (!player->streamer) {
6038 LOGD("no need to check streaming type");
6042 if (g_strrstr(player->type_caps_str, "application/x-hls")) {
6043 /* If it can't know exact type when it parses uri because of redirection case,
6044 * it will be fixed by typefinder or when doing autoplugging.
6046 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6047 player->streamer->is_adaptive_streaming = TRUE;
6048 } else if (g_strrstr(player->type_caps_str, "application/dash+xml")) {
6049 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6050 player->streamer->is_adaptive_streaming = TRUE;
6053 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6054 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type_caps_str, "video/mpegts"))) {
6055 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6057 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6058 if (player->streamer->is_adaptive_streaming)
6059 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6061 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6065 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6070 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6071 GstCaps *caps, gpointer data)
6073 mmplayer_t *player = (mmplayer_t *)data;
6077 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6079 MMPLAYER_FREEIF(player->type_caps_str);
6080 player->type_caps_str = gst_caps_to_string(caps);
6081 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6082 player, player->type_caps_str, probability, gst_caps_get_size(caps));
6084 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6085 (g_strrstr(player->type_caps_str, "audio/x-raw-int"))) {
6086 LOGE("not support media format");
6088 if (player->msg_posted == FALSE) {
6089 MMMessageParamType msg_param;
6090 memset(&msg_param, 0, sizeof(MMMessageParamType));
6092 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6093 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6095 /* don't post more if one was sent already */
6096 player->msg_posted = TRUE;
6101 __mmplayer_update_content_type_info(player);
6103 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6106 pad = gst_element_get_static_pad(tf, "src");
6108 LOGE("fail to get typefind src pad.");
6112 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6113 gboolean async = FALSE;
6114 LOGE("failed to autoplug %s", player->type_caps_str);
6116 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6118 if (async && player->msg_posted == FALSE)
6119 __mmplayer_handle_missed_plugin(player);
6121 gst_object_unref(GST_OBJECT(pad));
6128 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6130 GstElement *decodebin = NULL;
6134 /* create decodebin */
6135 decodebin = gst_element_factory_make("decodebin", NULL);
6138 LOGE("fail to create decodebin");
6142 /* raw pad handling signal */
6143 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6144 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6146 /* no-more-pad pad handling signal */
6147 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6148 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6150 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6151 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6153 /* This signal is emitted when a pad for which there is no further possible
6154 decoding is added to the decodebin.*/
6155 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6156 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6158 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6159 before looking for any elements that can handle that stream.*/
6160 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6161 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6163 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6164 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6165 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6167 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6168 before looking for any elements that can handle that stream.*/
6169 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6170 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6172 /* This signal is emitted once decodebin has finished decoding all the data.*/
6173 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6174 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6176 /* This signal is emitted when a element is added to the bin.*/
6177 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6178 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6185 __mmplayer_gst_make_queue2(mmplayer_t *player)
6187 GstElement *queue2 = NULL;
6188 gint64 dur_bytes = 0L;
6189 mmplayer_gst_element_t *mainbin = NULL;
6190 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6193 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6195 mainbin = player->pipeline->mainbin;
6197 queue2 = gst_element_factory_make("queue2", "queue2");
6199 LOGE("failed to create buffering queue element");
6203 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6204 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6206 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6208 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6209 * skip the pull mode(file or ring buffering) setting. */
6210 if (dur_bytes > 0) {
6211 if (!g_strrstr(player->type_caps_str, "video/mpegts")) {
6212 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6213 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6219 _mm_player_streaming_set_queue2(player->streamer,
6223 (guint64)dur_bytes); /* no meaning at the moment */
6229 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6231 mmplayer_gst_element_t *mainbin = NULL;
6232 GstElement *decodebin = NULL;
6233 GstElement *queue2 = NULL;
6234 GstPad *sinkpad = NULL;
6235 GstPad *qsrcpad = NULL;
6238 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6240 mainbin = player->pipeline->mainbin;
6242 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6244 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6245 LOGW("need to check: muxed buffer is not null");
6248 queue2 = __mmplayer_gst_make_queue2(player);
6250 LOGE("failed to make queue2");
6254 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6255 LOGE("failed to add buffering queue");
6259 sinkpad = gst_element_get_static_pad(queue2, "sink");
6260 qsrcpad = gst_element_get_static_pad(queue2, "src");
6262 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6263 LOGE("failed to link [%s:%s]-[%s:%s]",
6264 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6268 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6269 LOGE("failed to sync queue2 state with parent");
6273 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6274 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6278 gst_object_unref(GST_OBJECT(sinkpad));
6282 /* create decodebin */
6283 decodebin = _mmplayer_gst_make_decodebin(player);
6285 LOGE("failed to make decodebin");
6289 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6290 LOGE("failed to add decodebin");
6294 /* to force caps on the decodebin element and avoid reparsing stuff by
6295 * typefind. It also avoids a deadlock in the way typefind activates pads in
6296 * the state change */
6297 g_object_set(decodebin, "sink-caps", caps, NULL);
6299 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6301 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6302 LOGE("failed to link [%s:%s]-[%s:%s]",
6303 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6307 gst_object_unref(GST_OBJECT(sinkpad));
6309 gst_object_unref(GST_OBJECT(qsrcpad));
6312 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6313 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6315 /* set decodebin property about buffer in streaming playback. *
6316 * in case of HLS/DASH, it does not need to have big buffer *
6317 * because it is kind of adaptive streaming. */
6318 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6319 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6320 gint high_percent = 0;
6322 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6323 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6325 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6327 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6329 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6330 "high-percent", high_percent,
6331 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6332 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6333 "max-size-buffers", 0, NULL); // disable or automatic
6336 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6337 LOGE("failed to sync decodebin state with parent");
6348 gst_object_unref(GST_OBJECT(sinkpad));
6351 gst_object_unref(GST_OBJECT(qsrcpad));
6354 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6355 * You need to explicitly set elements to the NULL state before
6356 * dropping the final reference, to allow them to clean up.
6358 gst_element_set_state(queue2, GST_STATE_NULL);
6360 /* And, it still has a parent "player".
6361 * You need to let the parent manage the object instead of unreffing the object directly.
6363 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6364 LOGE("failed to remove queue2");
6365 gst_object_unref(queue2);
6371 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6372 * You need to explicitly set elements to the NULL state before
6373 * dropping the final reference, to allow them to clean up.
6375 gst_element_set_state(decodebin, GST_STATE_NULL);
6377 /* And, it still has a parent "player".
6378 * You need to let the parent manage the object instead of unreffing the object directly.
6381 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6382 LOGE("failed to remove decodebin");
6383 gst_object_unref(decodebin);
6392 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6396 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6397 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6399 LOGD("class : %s, mime : %s", factory_class, mime);
6401 /* add missing plugin */
6402 /* NOTE : msl should check missing plugin for image mime type.
6403 * Some motion jpeg clips can have playable audio track.
6404 * So, msl have to play audio after displaying popup written video format not supported.
6406 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6407 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6408 LOGD("not found demuxer");
6409 player->not_found_demuxer = TRUE;
6410 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6416 if (!g_strrstr(factory_class, "Demuxer")) {
6417 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6418 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6419 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6421 /* check that clip have multi tracks or not */
6422 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6423 LOGD("video plugin is already linked");
6425 LOGW("add VIDEO to missing plugin");
6426 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6427 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6429 } else if (g_str_has_prefix(mime, "audio")) {
6430 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6431 LOGD("audio plugin is already linked");
6433 LOGW("add AUDIO to missing plugin");
6434 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6435 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6443 return MM_ERROR_NONE;
6447 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6449 mmplayer_t *player = (mmplayer_t *)data;
6453 MMPLAYER_RETURN_IF_FAIL(player);
6455 /* remove fakesink. */
6456 if (!_mmplayer_gst_remove_fakesink(player,
6457 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6458 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6459 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6460 * source element are not same. To overcome this situation, this function will called
6461 * several places and several times. Therefore, this is not an error case.
6466 LOGD("[handle: %p] pipeline has completely constructed", player);
6468 if ((player->msg_posted == FALSE) &&
6469 (player->cmd >= MMPLAYER_COMMAND_START))
6470 __mmplayer_handle_missed_plugin(player);
6472 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6476 __mmplayer_check_profile(void)
6479 static int profile_tv = -1;
6481 if (__builtin_expect(profile_tv != -1, 1))
6484 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6485 switch (*profileName) {
6500 __mmplayer_get_next_uri(mmplayer_t *player)
6502 mmplayer_parse_profile_t profile;
6504 guint num_of_list = 0;
6507 num_of_list = g_list_length(player->uri_info.uri_list);
6508 uri_idx = player->uri_info.uri_idx;
6510 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6511 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6512 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6514 LOGW("next uri does not exist");
6518 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6519 LOGE("failed to parse profile");
6523 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6524 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6525 LOGW("uri type is not supported(%d)", profile.uri_type);
6529 LOGD("success to find next uri %d", uri_idx);
6533 if (!uri || uri_idx == num_of_list) {
6534 LOGE("failed to find next uri");
6538 player->uri_info.uri_idx = uri_idx;
6539 if (mm_player_set_attribute((MMHandleType)player, NULL,
6540 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6541 LOGE("failed to set attribute");
6545 if (!MMPLAYER_USE_DECODEBIN(player)) {
6546 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6547 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6548 "uri", profile.uri, NULL);
6551 SECURE_LOGD("next playback uri: %s", uri);
6556 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6558 #define REPEAT_COUNT_INFINITE -1
6559 #define REPEAT_COUNT_MIN 2
6560 #define ORIGINAL_URI_ONLY 1
6562 MMHandleType attrs = 0;
6566 guint num_of_uri = 0;
6567 int profile_tv = -1;
6571 LOGD("checking for gapless play option");
6573 if (player->build_audio_offload) {
6574 LOGE("offload path is not supportable.");
6578 if (player->pipeline->textbin) {
6579 LOGE("subtitle path is enabled. gapless play is not supported.");
6583 attrs = MMPLAYER_GET_ATTRS(player);
6585 LOGE("fail to get attributes.");
6589 mm_attrs_multiple_get(player->attrs, NULL,
6590 "content_video_found", &video,
6591 "profile_play_count", &count,
6592 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6594 /* gapless playback is not supported in case of video at TV profile. */
6595 profile_tv = __mmplayer_check_profile();
6596 if (profile_tv && video) {
6597 LOGW("not support video gapless playback");
6601 /* check repeat count in case of audio */
6603 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6604 LOGW("gapless is disabled");
6608 num_of_uri = g_list_length(player->uri_info.uri_list);
6609 if (!MMPLAYER_USE_DECODEBIN(player))
6610 player->gapless.running = TRUE;
6612 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6614 if (num_of_uri == ORIGINAL_URI_ONLY) {
6615 /* audio looping path */
6616 if (count >= REPEAT_COUNT_MIN) {
6617 /* decrease play count */
6618 /* we succeeded to rewind. update play count and then wait for next EOS */
6620 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6621 } else if (count != REPEAT_COUNT_INFINITE) {
6622 LOGD("there is no next uri and no repeat");
6626 if (!MMPLAYER_USE_DECODEBIN(player)) {
6627 if (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst)
6628 g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst),
6629 "uri", player->profile.uri, NULL);
6632 LOGD("looping cnt %d", count);
6634 /* gapless playback path */
6635 if (!__mmplayer_get_next_uri(player)) {
6636 LOGE("failed to get next uri");
6643 LOGE("unable to play gapless path. EOS will be posted soon");
6648 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6650 GstPad *sinkpad = g_value_get_object (item);
6651 GstElement *element = GST_ELEMENT(user_data);
6652 if (!sinkpad || !element) {
6653 LOGE("invalid parameter");
6657 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6658 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6662 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6664 mmplayer_gst_element_t *sinkbin = NULL;
6665 main_element_id_e concatId = MMPLAYER_M_NUM;
6666 main_element_id_e sinkId = MMPLAYER_M_NUM;
6667 gboolean send_notice = FALSE;
6668 GstElement *element;
6672 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6674 LOGD("type %d", type);
6677 case MM_PLAYER_TRACK_TYPE_AUDIO:
6678 concatId = MMPLAYER_M_A_CONCAT;
6679 sinkId = MMPLAYER_A_BIN;
6680 sinkbin = player->pipeline->audiobin;
6682 case MM_PLAYER_TRACK_TYPE_VIDEO:
6683 concatId = MMPLAYER_M_V_CONCAT;
6684 sinkId = MMPLAYER_V_BIN;
6685 sinkbin = player->pipeline->videobin;
6688 case MM_PLAYER_TRACK_TYPE_TEXT:
6689 concatId = MMPLAYER_M_T_CONCAT;
6690 sinkId = MMPLAYER_T_BIN;
6691 sinkbin = player->pipeline->textbin;
6694 LOGE("requested type is not supportable");
6699 element = player->pipeline->mainbin[concatId].gst;
6703 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6704 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6705 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6706 if (srcpad && sinkpad) {
6707 /* after getting drained signal there is no data flows, so no need to do pad_block */
6708 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6709 gst_pad_unlink(srcpad, sinkpad);
6711 /* send custom event to sink pad to handle it at video sink */
6713 LOGD("send custom event to sinkpad");
6714 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6715 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6716 gst_pad_send_event(sinkpad, event);
6719 gst_object_unref(srcpad);
6720 gst_object_unref(sinkpad);
6723 LOGD("release concat request pad");
6724 /* release and unref requests pad from the selector */
6725 iter = gst_element_iterate_sink_pads(element);
6726 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6727 gst_iterator_resync(iter);
6728 gst_iterator_free(iter);
6734 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6736 mmplayer_track_t *selector = &player->track[type];
6737 mmplayer_gst_element_t *sinkbin = NULL;
6738 main_element_id_e selectorId = MMPLAYER_M_NUM;
6739 main_element_id_e sinkId = MMPLAYER_M_NUM;
6740 GstPad *srcpad = NULL;
6741 GstPad *sinkpad = NULL;
6742 gboolean send_notice = FALSE;
6745 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6747 LOGD("type %d", type);
6750 case MM_PLAYER_TRACK_TYPE_AUDIO:
6751 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6752 sinkId = MMPLAYER_A_BIN;
6753 sinkbin = player->pipeline->audiobin;
6755 case MM_PLAYER_TRACK_TYPE_VIDEO:
6756 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6757 sinkId = MMPLAYER_V_BIN;
6758 sinkbin = player->pipeline->videobin;
6761 case MM_PLAYER_TRACK_TYPE_TEXT:
6762 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6763 sinkId = MMPLAYER_T_BIN;
6764 sinkbin = player->pipeline->textbin;
6767 LOGE("requested type is not supportable");
6772 if (player->pipeline->mainbin[selectorId].gst) {
6775 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6777 if (selector->event_probe_id != 0)
6778 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6779 selector->event_probe_id = 0;
6781 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6782 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6784 if (srcpad && sinkpad) {
6785 /* after getting drained signal there is no data flows, so no need to do pad_block */
6786 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6787 gst_pad_unlink(srcpad, sinkpad);
6789 /* send custom event to sink pad to handle it at video sink */
6791 LOGD("send custom event to sinkpad");
6792 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6793 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6794 gst_pad_send_event(sinkpad, event);
6798 gst_object_unref(sinkpad);
6801 gst_object_unref(srcpad);
6804 LOGD("selector release");
6806 /* release and unref requests pad from the selector */
6807 for (n = 0; n < selector->streams->len; n++) {
6808 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6809 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6812 g_ptr_array_set_size(selector->streams, 0);
6814 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6815 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6816 player->pipeline->mainbin[selectorId].gst)) {
6817 LOGE("failed to remove selector");
6818 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6821 player->pipeline->mainbin[selectorId].gst = NULL;
6829 __mmplayer_deactivate_old_path(mmplayer_t *player)
6832 MMPLAYER_RETURN_IF_FAIL(player);
6834 if (MMPLAYER_USE_DECODEBIN(player)) {
6835 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6836 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6837 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6838 LOGE("deactivate selector error");
6842 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6843 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6844 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6845 LOGE("deactivate concat error");
6850 _mmplayer_track_destroy(player);
6851 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6853 if (player->streamer) {
6854 _mm_player_streaming_initialize(player->streamer, FALSE);
6855 _mm_player_streaming_destroy(player->streamer);
6856 player->streamer = NULL;
6859 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6865 if (!player->msg_posted) {
6866 MMMessageParamType msg = {0,};
6869 msg.code = MM_ERROR_PLAYER_INTERNAL;
6870 LOGE("gapless_uri_play> deactivate error");
6872 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6873 player->msg_posted = TRUE;
6879 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6881 int result = MM_ERROR_NONE;
6882 mmplayer_t *player = (mmplayer_t *)hplayer;
6885 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6886 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6888 if (mm_player_set_attribute(hplayer, NULL,
6889 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6890 LOGE("failed to set attribute");
6891 result = MM_ERROR_PLAYER_INTERNAL;
6893 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6894 LOGE("failed to add the original uri in the uri list.");
6902 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6904 mmplayer_t *player = (mmplayer_t *)hplayer;
6905 guint num_of_list = 0;
6909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6910 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6912 if (player->pipeline && player->pipeline->textbin) {
6913 LOGE("subtitle path is enabled.");
6914 return MM_ERROR_PLAYER_INVALID_STATE;
6917 num_of_list = g_list_length(player->uri_info.uri_list);
6919 if (is_first_path) {
6920 if (num_of_list == 0) {
6921 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6922 SECURE_LOGD("add original path : %s", uri);
6924 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6925 player->uri_info.uri_list = g_list_prepend(
6926 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6927 SECURE_LOGD("change original path : %s", uri);
6930 MMHandleType attrs = 0;
6931 attrs = MMPLAYER_GET_ATTRS(player);
6933 if (num_of_list == 0) {
6934 char *original_uri = NULL;
6937 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6939 if (!original_uri) {
6940 LOGE("there is no original uri.");
6941 return MM_ERROR_PLAYER_INVALID_STATE;
6944 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6945 player->uri_info.uri_idx = 0;
6947 SECURE_LOGD("add original path at first : %s", original_uri);
6951 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6952 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6956 return MM_ERROR_NONE;
6960 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6962 mmplayer_t *player = (mmplayer_t *)hplayer;
6963 char *next_uri = NULL;
6964 guint num_of_list = 0;
6967 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6969 num_of_list = g_list_length(player->uri_info.uri_list);
6971 if (num_of_list > 0) {
6972 gint uri_idx = player->uri_info.uri_idx;
6974 if (uri_idx < num_of_list - 1)
6979 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6980 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6982 *uri = g_strdup(next_uri);
6986 return MM_ERROR_NONE;
6990 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6991 GstCaps *caps, gpointer data)
6993 mmplayer_t *player = (mmplayer_t *)data;
6994 const gchar *klass = NULL;
6995 const gchar *mime = NULL;
6996 gchar *caps_str = NULL;
6998 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6999 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7000 caps_str = gst_caps_to_string(caps);
7002 LOGW("unknown type of caps : %s from %s",
7003 caps_str, GST_ELEMENT_NAME(elem));
7005 MMPLAYER_FREEIF(caps_str);
7007 /* There is no available codec. */
7008 _mmplayer_update_not_supported_codec_info(player, klass, mime);
7012 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
7013 GstCaps *caps, gpointer data)
7015 mmplayer_t *player = (mmplayer_t *)data;
7016 const char *mime = NULL;
7017 gboolean ret = TRUE;
7019 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7020 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7022 if (g_str_has_prefix(mime, "audio")) {
7023 GstStructure *caps_structure = NULL;
7024 gint samplerate = 0;
7026 gchar *caps_str = NULL;
7028 caps_structure = gst_caps_get_structure(caps, 0);
7029 gst_structure_get_int(caps_structure, "rate", &samplerate);
7030 gst_structure_get_int(caps_structure, "channels", &channels);
7032 if ((channels > 0 && samplerate == 0)) {
7033 LOGD("exclude audio...");
7037 caps_str = gst_caps_to_string(caps);
7038 /* set it directly because not sent by TAG */
7039 if (g_strrstr(caps_str, "mobile-xmf"))
7040 mm_player_set_attribute((MMHandleType)player, NULL,
7041 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7043 MMPLAYER_FREEIF(caps_str);
7044 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7045 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7046 LOGD("video is already linked, allow the stream switch");
7049 LOGD("video is already linked");
7053 LOGD("found new stream");
7060 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7062 gboolean ret = FALSE;
7063 GDBusConnection *conn = NULL;
7065 GVariant *result = NULL;
7066 const gchar *dbus_device_type = NULL;
7067 const gchar *dbus_ret = NULL;
7070 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7072 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7077 result = g_dbus_connection_call_sync(conn,
7078 "org.pulseaudio.Server",
7079 "/org/pulseaudio/StreamManager",
7080 "org.pulseaudio.StreamManager",
7081 "GetCurrentMediaRoutingPath",
7082 g_variant_new("(s)", "out"),
7083 G_VARIANT_TYPE("(ss)"),
7084 G_DBUS_CALL_FLAGS_NONE,
7088 if (!result || err) {
7089 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7094 /* device type is listed in stream-map.json at mmfw-sysconf */
7095 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7097 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7098 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7101 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7102 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7103 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7104 LOGD("audio offload is supportable");
7110 LOGD("audio offload is not supportable");
7113 g_variant_unref(result);
7115 g_object_unref(conn);
7120 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7122 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7123 gint64 position = 0;
7125 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7126 player->pipeline && player->pipeline->mainbin);
7128 MMPLAYER_CMD_LOCK(player);
7129 current_state = MMPLAYER_CURRENT_STATE(player);
7131 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7132 LOGW("getting current position failed in paused");
7134 _mmplayer_unrealize((MMHandleType)player);
7135 _mmplayer_realize((MMHandleType)player);
7137 _mmplayer_set_position((MMHandleType)player, position);
7139 /* async not to be blocked in streaming case */
7140 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7142 _mmplayer_pause((MMHandleType)player);
7144 if (current_state == MM_PLAYER_STATE_PLAYING)
7145 _mmplayer_start((MMHandleType)player);
7146 MMPLAYER_CMD_UNLOCK(player);
7148 LOGD("rebuilding audio pipeline is completed.");
7151 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7153 mmplayer_t *player = (mmplayer_t *)user_data;
7154 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7155 gboolean is_supportable = FALSE;
7157 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7158 LOGW("failed to get device type");
7160 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7162 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7163 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7164 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7165 LOGD("ignore this dev connected info");
7169 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7170 if (player->build_audio_offload == is_supportable) {
7171 LOGD("keep current pipeline without re-building");
7175 /* rebuild pipeline */
7176 LOGD("re-build pipeline - offload: %d", is_supportable);
7177 player->build_audio_offload = FALSE;
7178 __mmplayer_rebuild_audio_pipeline(player);
7184 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7186 unsigned int id = 0;
7188 if (player->audio_device_cb_id != 0) {
7189 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7193 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7194 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7195 LOGD("added device connected cb (%u)", id);
7196 player->audio_device_cb_id = id;
7198 LOGW("failed to add device connected cb");
7205 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7207 mmplayer_t *player = (mmplayer_t *)hplayer;
7210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7211 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7213 *activated = player->build_audio_offload;
7215 LOGD("offload activated : %d", (int)*activated);
7218 return MM_ERROR_NONE;
7222 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7225 this function need to be updated according to the supported media format
7226 @see player->ini.audio_offload_media_format */
7228 if (__mmplayer_is_only_mp3_type(player->type_caps_str)) {
7229 LOGD("offload supportable media format type");
7237 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7239 gboolean ret = FALSE;
7240 GstElementFactory *factory = NULL;
7243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7245 LOGD("current stream : %s, sink: %s", player->type_caps_str, player->ini.audio_offload_sink_element);
7246 if (!__mmplayer_is_offload_supported_type(player))
7249 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7250 LOGD("there is no audio offload sink");
7254 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7255 LOGW("there is no audio device type to support offload");
7259 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7261 LOGW("there is no installed audio offload sink element");
7264 gst_object_unref(factory);
7266 if (_mmplayer_acquire_hw_resource(player,
7267 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7268 LOGE("failed to acquire audio offload decoder resource");
7272 if (!__mmplayer_add_audio_device_connected_cb(player))
7275 if (!__mmplayer_is_audio_offload_device_type(player))
7278 LOGD("audio offload can be built");
7283 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7289 static GstAutoplugSelectResult
7290 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7292 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7293 int audio_offload = 0;
7295 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7296 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7298 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7299 LOGD("expose audio path to build offload output path");
7300 player->build_audio_offload = TRUE;
7301 /* update codec info */
7302 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7303 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7304 player->audiodec_linked = 1;
7306 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7310 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7311 And need to consider the multi-track audio content.
7312 There is no HW audio decoder in public. */
7314 /* set stream information */
7315 if (!player->audiodec_linked)
7316 _mmplayer_set_audio_attrs(player, caps);
7318 /* update codec info */
7319 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7320 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7321 player->audiodec_linked = 1;
7323 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7325 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7326 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7328 /* mark video decoder for acquire */
7329 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7330 LOGW("video decoder resource is already acquired, skip it.");
7331 ret = GST_AUTOPLUG_SELECT_SKIP;
7335 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7336 LOGE("failed to acquire video decoder resource");
7337 ret = GST_AUTOPLUG_SELECT_SKIP;
7340 player->interrupted_by_resource = FALSE;
7343 /* update codec info */
7344 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7345 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7346 player->videodec_linked = 1;
7354 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7355 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7357 #define DEFAULT_IDX 0xFFFF
7358 #define MIN_FACTORY_NUM 2
7359 mmplayer_t *player = (mmplayer_t *)data;
7360 GValueArray *new_factories = NULL;
7361 GValue val = { 0, };
7362 GstElementFactory *factory = NULL;
7363 const gchar *klass = NULL;
7364 gchar *factory_name = NULL;
7365 guint hw_dec_idx = DEFAULT_IDX;
7366 guint first_sw_dec_idx = DEFAULT_IDX;
7367 guint last_sw_dec_idx = DEFAULT_IDX;
7368 guint new_pos = DEFAULT_IDX;
7369 guint rm_pos = DEFAULT_IDX;
7370 int audio_codec_type;
7371 int video_codec_type;
7372 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7374 if (factories->n_values < MIN_FACTORY_NUM)
7377 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7378 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7381 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7383 for (int i = 0 ; i < factories->n_values ; i++) {
7384 gchar *hw_dec_info = NULL;
7385 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7387 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7389 LOGW("failed to get factory object");
7392 klass = gst_element_factory_get_klass(factory);
7393 factory_name = GST_OBJECT_NAME(factory);
7396 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7398 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7399 if (!player->need_audio_dec_sorting) {
7400 LOGD("sorting is not required");
7403 codec_type = audio_codec_type;
7404 hw_dec_info = player->ini.audiocodec_element_hw;
7405 sw_dec_info = player->ini.audiocodec_element_sw;
7406 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7407 if (!player->need_video_dec_sorting) {
7408 LOGD("sorting is not required");
7411 codec_type = video_codec_type;
7412 hw_dec_info = player->ini.videocodec_element_hw;
7413 sw_dec_info = player->ini.videocodec_element_sw;
7418 if (g_strrstr(factory_name, hw_dec_info)) {
7421 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7422 if (strstr(factory_name, sw_dec_info[j])) {
7423 last_sw_dec_idx = i;
7424 if (first_sw_dec_idx == DEFAULT_IDX) {
7425 first_sw_dec_idx = i;
7430 if (first_sw_dec_idx == DEFAULT_IDX)
7431 LOGW("unknown codec %s", factory_name);
7435 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7438 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7439 if (hw_dec_idx < first_sw_dec_idx)
7441 new_pos = first_sw_dec_idx;
7442 rm_pos = hw_dec_idx + 1;
7443 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7444 if (last_sw_dec_idx < hw_dec_idx)
7446 new_pos = last_sw_dec_idx + 1;
7447 rm_pos = hw_dec_idx;
7452 /* change position - insert H/W decoder according to the new position */
7453 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7455 LOGW("failed to get factory object");
7458 new_factories = g_value_array_copy(factories);
7459 g_value_init (&val, G_TYPE_OBJECT);
7460 g_value_set_object (&val, factory);
7461 g_value_array_insert(new_factories, new_pos, &val);
7462 g_value_unset (&val);
7463 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7465 for (int i = 0 ; i < new_factories->n_values ; i++) {
7466 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7468 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7469 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7471 LOGE("[Re-arranged] failed to get factory object");
7474 return new_factories;
7478 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7479 GstCaps *caps, GstElementFactory *factory, gpointer data)
7481 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7482 mmplayer_t *player = (mmplayer_t *)data;
7484 gchar *factory_name = NULL;
7485 gchar *caps_str = NULL;
7486 const gchar *klass = NULL;
7489 factory_name = GST_OBJECT_NAME(factory);
7490 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7491 caps_str = gst_caps_to_string(caps);
7493 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7495 /* store type string */
7496 if (player->type_caps_str == NULL) {
7497 player->type_caps_str = gst_caps_to_string(caps);
7498 __mmplayer_update_content_type_info(player);
7501 /* filtering exclude keyword */
7502 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7503 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7504 LOGW("skipping [%s] by exclude keyword [%s]",
7505 factory_name, player->ini.exclude_element_keyword[idx]);
7507 result = GST_AUTOPLUG_SELECT_SKIP;
7512 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7513 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7514 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7515 factory_name, player->ini.unsupported_codec_keyword[idx]);
7516 result = GST_AUTOPLUG_SELECT_SKIP;
7521 /* exclude webm format */
7522 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7523 * because webm format is not supportable.
7524 * If webm is disabled in "autoplug-continue", there is no state change
7525 * failure or error because the decodebin will expose the pad directly.
7526 * It make MSL invoke _prepare_async_callback.
7527 * So, we need to disable webm format in "autoplug-select" */
7528 if (caps_str && strstr(caps_str, "webm")) {
7529 LOGW("webm is not supported");
7530 result = GST_AUTOPLUG_SELECT_SKIP;
7534 /* check factory class for filtering */
7535 /* NOTE : msl don't need to use image plugins.
7536 * So, those plugins should be skipped for error handling.
7538 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7539 LOGD("skipping [%s] by not required", factory_name);
7540 result = GST_AUTOPLUG_SELECT_SKIP;
7544 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7545 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7546 // TO CHECK : subtitle if needed, add subparse exception.
7547 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7548 result = GST_AUTOPLUG_SELECT_SKIP;
7552 if (g_strrstr(factory_name, "mpegpsdemux")) {
7553 LOGD("skipping PS container - not support");
7554 result = GST_AUTOPLUG_SELECT_SKIP;
7558 if (g_strrstr(factory_name, "mssdemux"))
7559 player->smooth_streaming = TRUE;
7561 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7562 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7565 GstStructure *str = NULL;
7567 /* parsebin in adaptivedemux get error if there is no parser */
7568 if ((!g_strrstr(GST_ELEMENT_NAME(bin), "parsebin")) ||
7569 ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player)))) {
7570 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7572 /* don't make video because of not required */
7573 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7574 (!player->set_mode.video_export)) {
7575 LOGD("no need video decoding, expose pad");
7576 result = GST_AUTOPLUG_SELECT_EXPOSE;
7581 /* get w/h for omx state-tune */
7582 /* FIXME: deprecated? */
7583 str = gst_caps_get_structure(caps, 0);
7584 gst_structure_get_int(str, "width", &width);
7587 if (player->v_stream_caps) {
7588 gst_caps_unref(player->v_stream_caps);
7589 player->v_stream_caps = NULL;
7592 player->v_stream_caps = gst_caps_copy(caps);
7593 LOGD("take caps for video state tune");
7594 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7598 if (g_strrstr(klass, "Codec/Decoder")) {
7599 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7600 if (result != GST_AUTOPLUG_SELECT_TRY) {
7601 LOGW("skip add decoder");
7607 MMPLAYER_FREEIF(caps_str);
7613 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7616 int ret = MM_ERROR_NONE;
7617 mmplayer_t *player = (mmplayer_t *)data;
7618 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7619 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7620 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7623 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7625 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7627 if (MMPLAYER_USE_DECODEBIN(player))
7630 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7633 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7635 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7637 LOGD("remove videobin");
7638 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7639 GST_STATE_NULL, FALSE, timeout);
7640 if (ret != MM_ERROR_NONE) {
7641 LOGE("fail to change state of videobin to NULL");
7645 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7646 LOGE("failed to remove videobin");
7647 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7650 LOGD("remove concat");
7651 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7652 GST_STATE_NULL, FALSE, timeout);
7653 if (ret != MM_ERROR_NONE) {
7654 LOGE("fail to change state of concat to NULL");
7658 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7659 LOGE("failed to remove video concat");
7660 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7663 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7664 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7665 MMPLAYER_FREEIF(player->pipeline->videobin);
7667 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7668 if (ret != MM_ERROR_NONE)
7669 LOGE("failed to release overlay resources");
7671 player->videodec_linked = 0;
7673 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7678 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7680 mmplayer_t *player = (mmplayer_t *)data;
7683 MMPLAYER_RETURN_IF_FAIL(player);
7685 LOGD("got about to finish signal");
7687 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7688 LOGW("Fail to get cmd lock");
7692 if (!__mmplayer_verify_gapless_play_path(player)) {
7693 LOGD("decoding is finished.");
7694 if (MMPLAYER_USE_DECODEBIN(player)) {
7695 MMPLAYER_CMD_UNLOCK(player);
7700 if (MMPLAYER_USE_DECODEBIN(player)) {
7701 _mmplayer_set_reconfigure_state(player, TRUE);
7702 MMPLAYER_CMD_UNLOCK(player);
7703 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7704 __mmplayer_deactivate_old_path(player);
7706 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7707 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7708 MMPLAYER_CMD_UNLOCK(player);
7715 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7717 mmplayer_t *player = (mmplayer_t *)data;
7718 GstIterator *iter = NULL;
7719 GValue item = { 0, };
7721 gboolean done = FALSE;
7722 gboolean is_all_drained = TRUE;
7725 MMPLAYER_RETURN_IF_FAIL(player);
7727 LOGD("got drained signal");
7729 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7730 LOGW("Fail to get cmd lock");
7734 if (!__mmplayer_verify_gapless_play_path(player)) {
7735 LOGD("decoding is finished.");
7736 MMPLAYER_CMD_UNLOCK(player);
7740 _mmplayer_set_reconfigure_state(player, TRUE);
7741 MMPLAYER_CMD_UNLOCK(player);
7743 /* check decodebin src pads whether they received EOS or not */
7744 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7747 switch (gst_iterator_next(iter, &item)) {
7748 case GST_ITERATOR_OK:
7749 pad = g_value_get_object(&item);
7750 if (pad && !GST_PAD_IS_EOS(pad)) {
7751 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7752 is_all_drained = FALSE;
7755 g_value_reset(&item);
7757 case GST_ITERATOR_RESYNC:
7758 gst_iterator_resync(iter);
7760 case GST_ITERATOR_ERROR:
7761 case GST_ITERATOR_DONE:
7766 g_value_unset(&item);
7767 gst_iterator_free(iter);
7769 if (!is_all_drained) {
7770 LOGD("Wait util the all pads get EOS.");
7775 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7776 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7778 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7779 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7780 __mmplayer_deactivate_old_path(player);
7786 _mmplayer_gst_element_added(GstBin *bin, GstElement *element, gpointer data)
7788 mmplayer_t *player = (mmplayer_t *)data;
7789 const gchar *klass = NULL;
7790 gchar *factory_name = NULL;
7792 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7793 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7795 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7797 if (__mmplayer_add_dump_buffer_probe(player, element))
7798 LOGD("add buffer probe");
7800 if (g_strrstr(klass, "Decoder")) {
7801 if (g_strrstr(klass, "Audio")) {
7802 player->audio_decoders = g_list_append(player->audio_decoders,
7803 g_strdup(GST_ELEMENT_NAME(element)));
7805 /* update codec info */
7806 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7807 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7808 player->audiodec_linked = 1;
7809 } else if (g_strrstr(klass, "Video")) {
7810 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7811 /* update codec info */
7812 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7813 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7814 player->videodec_linked = 1;
7817 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7819 GstCaps *caps = NULL;
7820 GstStructure *str = NULL;
7821 const gchar *name = NULL;
7822 gboolean caps_ret = TRUE;
7824 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7825 if (caps_ret && str) {
7826 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7827 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7828 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7829 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7830 LOGD("Send SPS and PPS Insertion every IDR frame");
7834 gst_object_unref(GST_OBJECT(srcpad));
7838 } else if (g_strrstr(klass, "Demuxer")) {
7839 if (g_strrstr(klass, "Adaptive")) {
7840 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7841 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7843 MMPLAYER_FREEIF(player->type_caps_str);
7845 if (g_strrstr(factory_name, "hlsdemux")) {
7846 player->type_caps_str = g_strdup("application/x-hls");
7847 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7848 } else if (g_strrstr(factory_name, "dashdemux")) {
7849 player->type_caps_str = g_strdup("application/dash+xml");
7850 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7852 LOGE("not supported type");
7855 player->streamer->is_adaptive_streaming = TRUE;
7857 if (player->streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
7858 player->streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
7860 LOGD("max variant limit: %d, %d, %d, prebuffer time: %d ms",
7861 player->adaptive_info.limit.bandwidth,
7862 player->adaptive_info.limit.width,
7863 player->adaptive_info.limit.height,
7864 player->streamer->buffering_req.prebuffer_time);
7866 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7867 "max-bitrate", player->adaptive_info.limit.bandwidth,
7868 "max-video-width", player->adaptive_info.limit.width,
7869 "max-video-height", player->adaptive_info.limit.height,
7870 "low-watermark-time", (guint64)(player->streamer->buffering_req.prebuffer_time * GST_MSECOND),
7874 LOGD("plugged element is demuxer. take it");
7876 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7877 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7879 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7880 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7881 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7884 if (g_strrstr(factory_name, "mpegaudioparse")) {
7885 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7886 (__mmplayer_is_only_mp3_type(player->type_caps_str))) {
7887 LOGD("[mpegaudioparse] set streaming pull mode.");
7888 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7890 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7891 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7893 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7895 /* set mq unlinked cache size to avoid not-linked error */
7896 gboolean sync_by_running_time = FALSE;
7897 g_object_get(G_OBJECT(element), "sync-by-running-time", &sync_by_running_time, NULL);
7898 if (sync_by_running_time)
7899 g_object_set(G_OBJECT(element), "unlinked-cache-time", MQ_UNLINKED_CACHE_TIME, NULL);
7901 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7902 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7904 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7905 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7906 _mm_player_streaming_set_multiqueue(player->streamer, element);
7907 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7915 __mmplayer_release_misc(mmplayer_t *player)
7918 bool cur_mode = player->set_mode.rich_audio;
7921 MMPLAYER_RETURN_IF_FAIL(player);
7923 player->sent_bos = FALSE;
7924 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7926 player->seek_state = MMPLAYER_SEEK_NONE;
7928 player->total_bitrate = 0;
7929 player->total_maximum_bitrate = 0;
7931 player->not_found_demuxer = 0;
7933 player->last_position = 0;
7934 player->duration = 0;
7935 player->http_content_size = 0;
7936 player->not_supported_codec = MISSING_PLUGIN_NONE;
7937 player->can_support_codec = FOUND_PLUGIN_NONE;
7938 player->pending_seek.is_pending = false;
7939 player->pending_seek.pos = 0;
7940 player->msg_posted = FALSE;
7941 player->has_many_types = FALSE;
7942 player->is_subtitle_force_drop = FALSE;
7943 player->play_subtitle = FALSE;
7944 player->adjust_subtitle_pos = 0;
7945 player->has_closed_caption = FALSE;
7946 player->set_mode.video_export = false;
7947 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7948 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7950 player->set_mode.rich_audio = cur_mode;
7952 if (player->audio_device_cb_id > 0 &&
7953 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7954 LOGW("failed to remove audio device_connected_callback");
7955 player->audio_device_cb_id = 0;
7957 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7958 player->bitrate[i] = 0;
7959 player->maximum_bitrate[i] = 0;
7962 /* free memory related to audio effect */
7963 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7965 if (player->adaptive_info.var_list) {
7966 g_list_free_full(player->adaptive_info.var_list, g_free);
7967 player->adaptive_info.var_list = NULL;
7970 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7971 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7972 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7974 /* Reset video360 settings to their defaults in case if the pipeline is to be
7977 player->video360_metadata.is_spherical = -1;
7978 player->is_openal_plugin_used = FALSE;
7980 player->is_content_spherical = FALSE;
7981 player->is_video360_enabled = TRUE;
7982 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7983 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7984 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7985 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7986 player->video360_zoom = 1.0f;
7987 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7988 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7990 player->sound.rg_enable = false;
7992 __mmplayer_initialize_video_roi(player);
7997 __mmplayer_release_misc_post(mmplayer_t *player)
7999 gchar *original_uri = NULL;
8002 /* player->pipeline is already released before. */
8003 MMPLAYER_RETURN_IF_FAIL(player);
8005 player->video_decoded_cb = NULL;
8006 player->video_decoded_cb_user_param = NULL;
8007 player->video_stream_prerolled = false;
8009 player->audio_decoded_cb = NULL;
8010 player->audio_decoded_cb_user_param = NULL;
8011 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
8013 player->audio_stream_changed_cb = NULL;
8014 player->audio_stream_changed_cb_user_param = NULL;
8016 mm_player_set_attribute((MMHandleType)player, NULL,
8017 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
8019 /* clean found audio decoders */
8020 if (player->audio_decoders) {
8021 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
8022 player->audio_decoders = NULL;
8025 /* clean the uri list except original uri */
8026 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
8028 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8029 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
8030 g_list_free_full(tmp, (GDestroyNotify)g_free);
8033 LOGW("failed to get original uri info");
8035 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
8036 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
8037 MMPLAYER_FREEIF(original_uri);
8040 /* clear the audio stream buffer list */
8041 _mmplayer_audio_stream_clear_buffer(player, FALSE);
8043 /* clear the video stream bo list */
8044 __mmplayer_video_stream_destroy_bo_list(player);
8045 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8047 if (player->profile.input_mem.buf) {
8048 free(player->profile.input_mem.buf);
8049 player->profile.input_mem.buf = NULL;
8051 player->profile.input_mem.len = 0;
8052 player->profile.input_mem.offset = 0;
8054 player->uri_info.uri_idx = 0;
8059 __mmplayer_check_subtitle(mmplayer_t *player)
8061 MMHandleType attrs = 0;
8062 char *subtitle_uri = NULL;
8066 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8068 /* get subtitle attribute */
8069 attrs = MMPLAYER_GET_ATTRS(player);
8070 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
8072 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8073 if (!subtitle_uri || (strlen(subtitle_uri) == 0)) {
8078 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8086 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8088 MMPLAYER_RETURN_IF_FAIL(player);
8090 if (player->eos_timer) {
8091 LOGD("cancel eos timer");
8092 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8093 player->eos_timer = 0;
8100 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8104 MMPLAYER_RETURN_IF_FAIL(player);
8105 MMPLAYER_RETURN_IF_FAIL(sink);
8108 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8110 player->sink_elements = g_list_append(player->sink_elements, sink);
8116 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8120 MMPLAYER_RETURN_IF_FAIL(player);
8121 MMPLAYER_RETURN_IF_FAIL(sink);
8123 player->sink_elements = g_list_remove(player->sink_elements, sink);
8129 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8130 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8132 mmplayer_signal_item_t *item = NULL;
8135 MMPLAYER_RETURN_IF_FAIL(player);
8137 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8138 LOGE("invalid signal type [%d]", type);
8142 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8144 LOGE("cannot connect signal [%s]", signal);
8149 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8150 player->signals[type] = g_list_append(player->signals[type], item);
8156 /* NOTE : be careful with calling this api. please refer to below glib comment
8157 * glib comment : Note that there is a bug in GObject that makes this function much
8158 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8159 * will no longer be called, but, the signal handler is not currently disconnected.
8160 * If the instance is itself being freed at the same time than this doesn't matter,
8161 * since the signal will automatically be removed, but if instance persists,
8162 * then the signal handler will leak. You should not remove the signal yourself
8163 * because in a future versions of GObject, the handler will automatically be
8166 * It's possible to work around this problem in a way that will continue to work
8167 * with future versions of GObject by checking that the signal handler is still
8168 * connected before disconnected it:
8170 * if (g_signal_handler_is_connected(instance, id))
8171 * g_signal_handler_disconnect(instance, id);
8174 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8176 GList *sig_list = NULL;
8177 mmplayer_signal_item_t *item = NULL;
8181 MMPLAYER_RETURN_IF_FAIL(player);
8183 LOGD("release signals type : %d", type);
8185 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8186 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8187 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8188 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8189 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8190 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8194 sig_list = player->signals[type];
8196 for (; sig_list; sig_list = sig_list->next) {
8197 item = sig_list->data;
8199 if (item && item->obj) {
8200 if (g_signal_handler_is_connected(item->obj, item->sig))
8201 g_signal_handler_disconnect(item->obj, item->sig);
8204 MMPLAYER_FREEIF(item);
8207 g_list_free(player->signals[type]);
8208 player->signals[type] = NULL;
8216 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8218 mmplayer_t *player = 0;
8219 int prev_display_surface_type = 0;
8223 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8225 player = MM_PLAYER_CAST(handle);
8227 /* check video sinkbin is created */
8228 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8229 LOGW("Videosink is already created");
8230 return MM_ERROR_NONE;
8233 LOGD("videosink element is not yet ready");
8235 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8236 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8238 return MM_ERROR_INVALID_ARGUMENT;
8241 /* load previous attributes */
8242 if (player->attrs) {
8243 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8244 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8245 if (prev_display_surface_type == surface_type) {
8246 LOGD("incoming display surface type is same as previous one, do nothing..");
8248 return MM_ERROR_NONE;
8251 LOGE("failed to load attributes");
8253 return MM_ERROR_PLAYER_INTERNAL;
8256 /* videobin is not created yet, so we just set attributes related to display surface */
8257 LOGD("store display attribute for given surface type(%d)", surface_type);
8258 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8259 "display_overlay", wl_surface_id, NULL);
8262 return MM_ERROR_NONE;
8265 /* Note : if silent is true, then subtitle would not be displayed. :*/
8267 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8269 mmplayer_t *player = (mmplayer_t *)hplayer;
8273 /* check player handle */
8274 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8276 player->set_mode.subtitle_off = silent;
8278 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8282 return MM_ERROR_NONE;
8286 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8288 mmplayer_gst_element_t *mainbin = NULL;
8289 mmplayer_gst_element_t *textbin = NULL;
8290 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8291 GstState current_state = GST_STATE_VOID_PENDING;
8292 GstState element_state = GST_STATE_VOID_PENDING;
8293 GstState element_pending_state = GST_STATE_VOID_PENDING;
8295 GstEvent *event = NULL;
8296 int result = MM_ERROR_NONE;
8298 GstClock *curr_clock = NULL;
8299 GstClockTime base_time, start_time, curr_time;
8304 /* check player handle */
8305 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8307 player->pipeline->mainbin &&
8308 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8310 mainbin = player->pipeline->mainbin;
8311 textbin = player->pipeline->textbin;
8313 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8315 // sync clock with current pipeline
8316 curr_clock = gst_element_get_clock(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8317 curr_time = gst_clock_get_time(curr_clock);
8319 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8320 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8322 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8323 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8325 if (current_state > GST_STATE_READY) {
8326 // sync state with current pipeline
8327 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8328 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8329 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8331 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8332 if (GST_STATE_CHANGE_FAILURE == ret) {
8333 LOGE("fail to state change.");
8334 result = MM_ERROR_PLAYER_INTERNAL;
8336 gst_object_unref(curr_clock);
8340 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8341 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8344 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8345 gst_object_unref(curr_clock);
8348 // seek to current position
8349 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8350 result = MM_ERROR_PLAYER_INVALID_STATE;
8351 LOGE("gst_element_query_position failed, invalid state");
8355 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8356 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);
8358 result = MM_ERROR_PLAYER_INTERNAL;
8359 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8363 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
8364 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
8365 if (GST_IS_ELEMENT(text_sink)) {
8366 if (gst_element_send_event(text_sink, event))
8367 LOGD("sending event[%s] to subtitle sink element [%s] success!",
8368 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8370 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
8371 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8374 _mmplayer_gst_send_event_to_sink(player, event);
8377 /* sync state with current pipeline */
8378 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8379 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8380 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8382 return MM_ERROR_NONE;
8385 /* release text pipeline resource */
8386 player->textsink_linked = 0;
8388 /* release signal */
8389 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8391 /* release textbin with it's children */
8392 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8393 MMPLAYER_FREEIF(player->pipeline->textbin);
8394 player->pipeline->textbin = NULL;
8396 /* release subtitle elem */
8397 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8398 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8404 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8406 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8407 GstState current_state = GST_STATE_VOID_PENDING;
8409 MMHandleType attrs = 0;
8410 mmplayer_gst_element_t *mainbin = NULL;
8411 mmplayer_gst_element_t *textbin = NULL;
8413 gchar *subtitle_uri = NULL;
8414 int result = MM_ERROR_NONE;
8415 const gchar *charset = NULL;
8419 /* check player handle */
8420 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8422 player->pipeline->mainbin &&
8423 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8424 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8426 mainbin = player->pipeline->mainbin;
8427 textbin = player->pipeline->textbin;
8429 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8430 if (current_state < GST_STATE_READY) {
8431 result = MM_ERROR_PLAYER_INVALID_STATE;
8432 LOGE("Pipeline is not in proper state");
8436 attrs = MMPLAYER_GET_ATTRS(player);
8438 LOGE("cannot get content attribute");
8439 result = MM_ERROR_PLAYER_INTERNAL;
8443 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8444 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8445 LOGE("subtitle uri is not proper filepath");
8446 result = MM_ERROR_PLAYER_INVALID_URI;
8450 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8451 LOGE("failed to get storage info of subtitle path");
8452 result = MM_ERROR_PLAYER_INVALID_URI;
8456 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8457 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8459 if (!strcmp(filepath, subtitle_uri)) {
8460 LOGD("subtitle path is not changed");
8463 if (mm_player_set_attribute((MMHandleType)player, NULL,
8464 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8465 LOGE("failed to set attribute");
8470 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8471 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8472 player->subtitle_language_list = NULL;
8473 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8475 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8476 if (ret != GST_STATE_CHANGE_SUCCESS) {
8477 LOGE("failed to change state of textbin to READY");
8478 result = MM_ERROR_PLAYER_INTERNAL;
8482 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8483 if (ret != GST_STATE_CHANGE_SUCCESS) {
8484 LOGE("failed to change state of subparse to READY");
8485 result = MM_ERROR_PLAYER_INTERNAL;
8489 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8490 if (ret != GST_STATE_CHANGE_SUCCESS) {
8491 LOGE("failed to change state of filesrc to READY");
8492 result = MM_ERROR_PLAYER_INTERNAL;
8496 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8498 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8500 charset = _mmplayer_get_charset(filepath);
8502 LOGD("detected charset is %s", charset);
8503 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8506 result = _mmplayer_sync_subtitle_pipeline(player);
8513 /* API to switch between external subtitles */
8515 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8517 int result = MM_ERROR_NONE;
8518 mmplayer_t *player = (mmplayer_t *)hplayer;
8523 /* check player handle */
8524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526 /* filepath can be null in idle state */
8528 /* check file path */
8529 if ((path = strstr(filepath, "file://")))
8530 result = _mmplayer_exist_file_path(path + 7);
8532 result = _mmplayer_exist_file_path(filepath);
8534 if (result != MM_ERROR_NONE) {
8535 LOGE("invalid subtitle path 0x%X", result);
8536 return result; /* file not found or permission denied */
8540 if (!player->pipeline) {
8542 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8543 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8544 LOGE("failed to set attribute");
8545 return MM_ERROR_PLAYER_INTERNAL;
8548 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8549 /* check filepath */
8550 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8552 if (!__mmplayer_check_subtitle(player)) {
8553 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8554 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8555 LOGE("failed to set attribute");
8556 return MM_ERROR_PLAYER_INTERNAL;
8559 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8560 LOGE("fail to create text pipeline");
8561 return MM_ERROR_PLAYER_INTERNAL;
8564 result = _mmplayer_sync_subtitle_pipeline(player);
8566 result = __mmplayer_change_external_subtitle_language(player, filepath);
8569 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8570 player->is_external_subtitle_added_now = TRUE;
8572 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8573 if (!player->subtitle_language_list) {
8574 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8575 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8576 LOGW("subtitle language list is not updated yet");
8578 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8580 player->is_external_subtitle_present = TRUE;
8587 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8589 guint active_idx = 0;
8590 GstStream *stream = NULL;
8591 GList *streams = NULL;
8592 GstCaps *caps = NULL;
8595 LOGD("Switching Streams... type: %d, index: %d", type, index);
8597 player->track[type].active_track_index = index;
8599 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8600 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8601 LOGD("track type:%d, total: %d, active: %d", i,
8602 player->track[i].total_track_num, player->track[i].active_track_index);
8603 if (player->track[i].total_track_num > 0 &&
8604 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8605 active_idx = player->track[i].active_track_index;
8606 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8607 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8608 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8610 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8611 caps = gst_stream_get_caps(stream);
8613 _mmplayer_set_audio_attrs(player, caps);
8614 gst_caps_unref(caps);
8621 LOGD("send select stream event");
8622 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8623 gst_event_new_select_streams(streams));
8624 g_list_free(streams);
8627 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8628 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8629 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8631 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8632 pos_nsec = player->last_position;
8634 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8636 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8637 player->playback_rate, GST_FORMAT_TIME,
8638 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8639 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8640 LOGW("failed to seek");
8641 return MM_ERROR_PLAYER_INTERNAL;
8646 return MM_ERROR_NONE;
8650 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8652 int result = MM_ERROR_NONE;
8653 gchar *change_pad_name = NULL;
8654 GstPad *sinkpad = NULL;
8655 mmplayer_gst_element_t *mainbin = NULL;
8656 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8657 GstCaps *caps = NULL;
8658 gint total_track_num = 0;
8662 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8663 MM_ERROR_PLAYER_NOT_INITIALIZED);
8665 LOGD("Change Track(%d) to %d", type, index);
8667 mainbin = player->pipeline->mainbin;
8669 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8670 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8671 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8672 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8674 /* Changing Video Track is not supported. */
8675 LOGE("Track Type Error");
8679 if (mainbin[elem_idx].gst == NULL) {
8680 result = MM_ERROR_PLAYER_NO_OP;
8681 LOGD("Req track doesn't exist");
8685 total_track_num = player->track[type].total_track_num;
8686 if (total_track_num <= 0) {
8687 result = MM_ERROR_PLAYER_NO_OP;
8688 LOGD("Language list is not available");
8692 if ((index < 0) || (index >= total_track_num)) {
8693 result = MM_ERROR_INVALID_ARGUMENT;
8694 LOGD("Not a proper index : %d", index);
8698 /*To get the new pad from the selector*/
8699 change_pad_name = g_strdup_printf("sink_%u", index);
8700 if (change_pad_name == NULL) {
8701 result = MM_ERROR_PLAYER_INTERNAL;
8702 LOGD("Pad does not exists");
8706 LOGD("new active pad name: %s", change_pad_name);
8708 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8709 if (sinkpad == NULL) {
8710 LOGD("sinkpad is NULL");
8711 result = MM_ERROR_PLAYER_INTERNAL;
8715 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8716 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8718 caps = gst_pad_get_current_caps(sinkpad);
8719 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8722 gst_object_unref(sinkpad);
8724 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8725 _mmplayer_set_audio_attrs(player, caps);
8728 gst_caps_unref(caps);
8731 MMPLAYER_FREEIF(change_pad_name);
8736 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8738 int result = MM_ERROR_NONE;
8739 mmplayer_t *player = NULL;
8740 mmplayer_gst_element_t *mainbin = NULL;
8742 gint current_active_index = 0;
8744 GstState current_state = GST_STATE_VOID_PENDING;
8749 player = (mmplayer_t *)hplayer;
8750 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8751 MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_PLAYER_NOT_INITIALIZED);
8753 if (!player->pipeline) {
8754 LOGE("Track %d pre setting -> %d", type, index);
8756 player->track[type].active_track_index = index;
8760 mainbin = player->pipeline->mainbin;
8762 current_active_index = player->track[type].active_track_index;
8764 /*If index is same as running index no need to change the pad*/
8765 if (current_active_index == index)
8768 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8769 result = MM_ERROR_PLAYER_INVALID_STATE;
8773 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8774 if (current_state < GST_STATE_PAUSED) {
8775 result = MM_ERROR_PLAYER_INVALID_STATE;
8776 LOGW("Pipeline not in proper state");
8780 if (MMPLAYER_USE_DECODEBIN(player))
8781 result = __mmplayer_change_selector_pad(player, type, index);
8783 result = __mmplayer_switch_stream(player, type, index);
8785 if (result != MM_ERROR_NONE) {
8786 LOGE("failed to change track");
8790 player->track[type].active_track_index = index;
8792 if (MMPLAYER_USE_DECODEBIN(player)) {
8793 GstEvent *event = NULL;
8794 if (current_state == GST_STATE_PLAYING) {
8795 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8796 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8797 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8799 _mmplayer_gst_send_event_to_sink(player, event);
8801 result = MM_ERROR_PLAYER_INTERNAL;
8812 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8814 mmplayer_t *player = (mmplayer_t *)hplayer;
8818 /* check player handle */
8819 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8821 *silent = player->set_mode.subtitle_off;
8823 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8827 return MM_ERROR_NONE;
8831 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8833 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8834 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8836 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8837 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8841 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8842 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8843 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8844 mmplayer_dump_t *dump_s;
8845 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8846 if (dump_s == NULL) {
8847 LOGE("malloc fail");
8851 dump_s->dump_element_file = NULL;
8852 dump_s->dump_pad = NULL;
8853 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8855 if (dump_s->dump_pad) {
8856 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8857 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]);
8858 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8859 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);
8860 /* add list for removed buffer probe and close FILE */
8861 player->dump_list = g_list_append(player->dump_list, dump_s);
8862 LOGD("%s sink pad added buffer probe for dump", factory_name);
8865 MMPLAYER_FREEIF(dump_s);
8866 LOGE("failed to get %s sink pad added", factory_name);
8873 static GstPadProbeReturn
8874 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8876 FILE *dump_data = (FILE *)u_data;
8878 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8879 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8881 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8883 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8885 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8887 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8889 gst_buffer_unmap(buffer, &probe_info);
8891 return GST_PAD_PROBE_OK;
8895 __mmplayer_release_dump_list(GList *dump_list)
8897 GList *d_list = dump_list;
8902 for (; d_list; d_list = g_list_next(d_list)) {
8903 mmplayer_dump_t *dump_s = d_list->data;
8904 if (dump_s->dump_pad) {
8905 if (dump_s->probe_handle_id)
8906 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8907 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8909 if (dump_s->dump_element_file) {
8910 fclose(dump_s->dump_element_file);
8911 dump_s->dump_element_file = NULL;
8913 MMPLAYER_FREEIF(dump_s);
8915 g_list_free(dump_list);
8920 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8922 mmplayer_t *player = (mmplayer_t *)hplayer;
8926 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8927 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8929 *exist = (bool)player->has_closed_caption;
8933 return MM_ERROR_NONE;
8937 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8942 LOGD("unref internal gst buffer %p", buffer);
8944 gst_buffer_unref((GstBuffer *)buffer);
8951 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8953 mmplayer_t *player = (mmplayer_t *)hplayer;
8957 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8958 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8960 if (MMPLAYER_IS_STREAMING(player))
8961 *timeout = (int)player->ini.live_state_change_timeout;
8963 *timeout = (int)player->ini.localplayback_state_change_timeout;
8965 LOGD("timeout = %d", *timeout);
8968 return MM_ERROR_NONE;
8972 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8976 MMPLAYER_RETURN_IF_FAIL(player);
8978 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8980 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8981 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8982 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8983 player->storage_info[i].id = -1;
8984 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8986 if (path_type != MMPLAYER_PATH_MAX)
8995 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8997 int ret = MM_ERROR_NONE;
8998 mmplayer_t *player = (mmplayer_t *)hplayer;
8999 MMMessageParamType msg_param = {0, };
9002 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9004 LOGW("state changed storage %d:%d", id, state);
9006 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
9007 return MM_ERROR_NONE;
9009 /* FIXME: text path should be handled separately. */
9010 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
9011 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9012 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
9013 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9014 LOGW("external storage is removed");
9016 if (player->msg_posted == FALSE) {
9017 memset(&msg_param, 0, sizeof(MMMessageParamType));
9018 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9019 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9020 player->msg_posted = TRUE;
9023 /* unrealize the player */
9024 ret = _mmplayer_unrealize(hplayer);
9025 if (ret != MM_ERROR_NONE)
9026 LOGE("failed to unrealize");
9034 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9036 int ret = MM_ERROR_NONE;
9037 mmplayer_t *player = (mmplayer_t *)hplayer;
9038 int idx = 0, total = 0;
9039 gchar *result = NULL, *tmp = NULL;
9042 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9043 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9045 total = *num = g_list_length(player->adaptive_info.var_list);
9047 LOGW("There is no stream variant info.");
9051 result = g_strdup("");
9052 for (idx = 0 ; idx < total ; idx++) {
9053 stream_variant_t *v_data = NULL;
9054 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9057 gchar data[64] = {0};
9058 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9060 tmp = g_strconcat(result, data, NULL);
9064 LOGW("There is no variant data in %d", idx);
9069 *var_info = (char *)result;
9071 LOGD("variant info %d:%s", *num, *var_info);
9077 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9079 int ret = MM_ERROR_NONE;
9080 mmplayer_t *player = (mmplayer_t *)hplayer;
9083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9085 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9087 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9088 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9089 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9091 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9092 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9093 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9094 "max-bitrate", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9096 /* FIXME: seek to current position for applying new variant limitation */
9105 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9107 int ret = MM_ERROR_NONE;
9108 mmplayer_t *player = (mmplayer_t *)hplayer;
9111 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9112 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9114 *bandwidth = player->adaptive_info.limit.bandwidth;
9115 *width = player->adaptive_info.limit.width;
9116 *height = player->adaptive_info.limit.height;
9118 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9125 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9127 int ret = MM_ERROR_NONE;
9128 mmplayer_t *player = (mmplayer_t *)hplayer;
9131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9132 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9133 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9135 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9137 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9138 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9139 else /* live case */
9140 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9142 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9149 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9151 #define IDX_FIRST_SW_CODEC 0
9152 mmplayer_t *player = (mmplayer_t *)hplayer;
9153 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9154 const char *attr_name = NULL;
9155 const char *default_type = NULL;
9156 const char *element_hw = NULL;
9157 const char *element_sw = NULL;
9160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9162 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9164 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9165 switch (stream_type) {
9166 case MM_PLAYER_STREAM_TYPE_AUDIO:
9167 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9168 default_type = player->ini.audiocodec_default_type;
9169 element_hw = player->ini.audiocodec_element_hw;
9170 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9172 case MM_PLAYER_STREAM_TYPE_VIDEO:
9173 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9174 default_type = player->ini.videocodec_default_type;
9175 element_hw = player->ini.videocodec_element_hw;
9176 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9179 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9180 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9184 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9186 if (!strcmp(default_type, "sw"))
9187 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9189 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9191 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9192 codec_type = default_codec_type;
9194 /* to support codec selection, codec info have to be added in ini file.
9195 in case of hw codec is selected, filter elements should be applied
9196 depending on the hw capabilities. */
9197 if (codec_type != default_codec_type) {
9198 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9199 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9200 LOGE("There is no codec for type %d", codec_type);
9201 return MM_ERROR_PLAYER_NO_OP;
9204 LOGD("sorting is required");
9205 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9206 player->need_audio_dec_sorting = TRUE;
9208 player->need_video_dec_sorting = TRUE;
9211 LOGD("update %s codec_type to %d", attr_name, codec_type);
9212 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9215 return MM_ERROR_NONE;
9219 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9221 mmplayer_t *player = (mmplayer_t *)hplayer;
9222 GstElement *rg_vol_element = NULL;
9226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9228 player->sound.rg_enable = enabled;
9230 /* just hold rgvolume enable value if pipeline is not ready */
9231 if (!player->pipeline || !player->pipeline->audiobin) {
9232 LOGD("pipeline is not ready. holding rgvolume enable value");
9233 return MM_ERROR_NONE;
9236 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9238 if (!rg_vol_element) {
9239 LOGD("rgvolume element is not created");
9240 return MM_ERROR_PLAYER_INTERNAL;
9244 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9246 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9250 return MM_ERROR_NONE;
9254 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9256 mmplayer_t *player = (mmplayer_t *)hplayer;
9257 GstElement *rg_vol_element = NULL;
9258 gboolean enable = FALSE;
9262 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9263 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9265 /* just hold enable_rg value if pipeline is not ready */
9266 if (!player->pipeline || !player->pipeline->audiobin) {
9267 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9268 *enabled = player->sound.rg_enable;
9269 return MM_ERROR_NONE;
9272 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9274 if (!rg_vol_element) {
9275 LOGD("rgvolume element is not created");
9276 return MM_ERROR_PLAYER_INTERNAL;
9279 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9280 *enabled = (bool)enable;
9284 return MM_ERROR_NONE;
9288 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9290 mmplayer_t *player = (mmplayer_t *)hplayer;
9291 MMHandleType attrs = 0;
9293 int ret = MM_ERROR_NONE;
9297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9299 attrs = MMPLAYER_GET_ATTRS(player);
9300 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9302 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9304 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9305 return MM_ERROR_PLAYER_INTERNAL;
9308 player->video_roi.scale_x = scale_x;
9309 player->video_roi.scale_y = scale_y;
9310 player->video_roi.scale_width = scale_width;
9311 player->video_roi.scale_height = scale_height;
9313 /* check video sinkbin is created */
9314 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9315 return MM_ERROR_NONE;
9317 if (!gst_video_overlay_set_video_roi_area(
9318 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9319 scale_x, scale_y, scale_width, scale_height))
9320 ret = MM_ERROR_PLAYER_INTERNAL;
9322 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9323 scale_x, scale_y, scale_width, scale_height);
9331 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9333 mmplayer_t *player = (mmplayer_t *)hplayer;
9334 int ret = MM_ERROR_NONE;
9338 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9339 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9341 *scale_x = player->video_roi.scale_x;
9342 *scale_y = player->video_roi.scale_y;
9343 *scale_width = player->video_roi.scale_width;
9344 *scale_height = player->video_roi.scale_height;
9346 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9347 *scale_x, *scale_y, *scale_width, *scale_height);
9353 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9355 mmplayer_t *player = (mmplayer_t *)hplayer;
9359 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9361 player->client_pid = pid;
9363 LOGD("client pid[%d] %p", pid, player);
9367 return MM_ERROR_NONE;
9371 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9373 mmplayer_t *player = (mmplayer_t *)hplayer;
9374 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9375 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9380 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9383 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9385 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9387 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9388 return MM_ERROR_NONE;
9390 /* in case of audio codec default type is HW */
9392 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9393 if (player->ini.support_audio_effect)
9394 return MM_ERROR_NONE;
9395 elem_id = MMPLAYER_A_FILTER;
9397 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9398 if (player->ini.support_replaygain_control)
9399 return MM_ERROR_NONE;
9400 elem_id = MMPLAYER_A_RGVOL;
9402 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9403 if (player->ini.support_pitch_control)
9404 return MM_ERROR_NONE;
9405 elem_id = MMPLAYER_A_PITCH;
9407 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9408 if (player->ini.support_audio_effect)
9409 return MM_ERROR_NONE;
9411 /* default case handling is not required */
9414 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9415 LOGW("audio control option [%d] is not available", opt);
9418 /* setting pcm exporting option is allowed before READY state */
9419 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9420 return MM_ERROR_PLAYER_INVALID_STATE;
9422 /* check whether the audio filter exist or not after READY state,
9423 because the sw codec could be added during auto-plugging in some cases */
9424 if (!player->pipeline ||
9425 !player->pipeline->audiobin ||
9426 !player->pipeline->audiobin[elem_id].gst) {
9427 LOGW("there is no audio elem [%d]", elem_id);
9432 LOGD("audio control opt %d, available %d", opt, *available);
9436 return MM_ERROR_NONE;
9440 __mmplayer_update_duration_value(mmplayer_t *player)
9442 gboolean ret = FALSE;
9443 gint64 dur_nsec = 0;
9444 LOGD("try to update duration");
9446 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9447 player->duration = dur_nsec;
9448 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9452 if (player->duration < 0) {
9453 LOGW("duration is Non-Initialized !!!");
9454 player->duration = 0;
9457 /* update streaming service type */
9458 player->streaming_type = _mmplayer_get_stream_service_type(player);
9460 /* check duration is OK */
9461 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9462 /* FIXIT : find another way to get duration here. */
9463 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9469 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9471 /* update audio params
9472 NOTE : We need original audio params and it can be only obtained from src pad of audio
9473 decoder. Below code only valid when we are not using 'resampler' just before
9474 'audioconverter'. */
9475 GstCaps *caps_a = NULL;
9477 gint samplerate = 0, channels = 0;
9478 GstStructure *p = NULL;
9479 GstElement *aconv = NULL;
9481 LOGD("try to update audio attrs");
9483 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9485 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9486 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9487 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9488 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9490 LOGE("there is no audio converter");
9494 pad = gst_element_get_static_pad(aconv, "sink");
9497 LOGW("failed to get pad from audio converter");
9501 caps_a = gst_pad_get_current_caps(pad);
9503 LOGW("not ready to get audio caps");
9504 gst_object_unref(pad);
9508 p = gst_caps_get_structure(caps_a, 0);
9509 gst_structure_get_int(p, "rate", &samplerate);
9510 gst_structure_get_int(p, "channels", &channels);
9512 mm_player_set_attribute((MMHandleType)player, NULL,
9513 "content_audio_samplerate", samplerate,
9514 "content_audio_channels", channels, NULL);
9516 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9518 gst_caps_unref(caps_a);
9519 gst_object_unref(pad);
9525 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9527 LOGD("try to update video attrs");
9529 GstCaps *caps_v = NULL;
9533 GstStructure *p = NULL;
9535 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9536 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9538 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9540 LOGD("no videosink sink pad");
9544 caps_v = gst_pad_get_current_caps(pad);
9545 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9546 if (!caps_v && player->v_stream_caps) {
9547 caps_v = player->v_stream_caps;
9548 gst_caps_ref(caps_v);
9552 LOGD("no negotiated caps from videosink");
9553 gst_object_unref(pad);
9557 p = gst_caps_get_structure(caps_v, 0);
9558 gst_structure_get_int(p, "width", &width);
9559 gst_structure_get_int(p, "height", &height);
9561 mm_player_set_attribute((MMHandleType)player, NULL,
9562 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9564 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9566 SECURE_LOGD("width : %d height : %d", width, height);
9568 gst_caps_unref(caps_v);
9569 gst_object_unref(pad);
9572 mm_player_set_attribute((MMHandleType)player, NULL,
9573 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9574 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9581 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9583 gboolean ret = FALSE;
9584 guint64 data_size = 0;
9588 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9589 if (!player->duration)
9592 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9593 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9594 if (stat(path, &sb) == 0)
9595 data_size = (guint64)sb.st_size;
9597 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9598 data_size = player->http_content_size;
9601 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9604 guint64 bitrate = 0;
9605 guint64 msec_dur = 0;
9607 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9609 bitrate = data_size * 8 * 1000 / msec_dur;
9610 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9611 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9612 mm_player_set_attribute((MMHandleType)player, NULL,
9613 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9616 LOGD("player duration is less than 0");
9620 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9621 if (player->total_bitrate) {
9622 mm_player_set_attribute((MMHandleType)player, NULL,
9623 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9632 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9634 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9635 data->uri_type = uri_type;
9639 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9641 int ret = MM_ERROR_PLAYER_INVALID_URI;
9643 char *buffer = NULL;
9644 char *seperator = strchr(path, ',');
9645 char ext[100] = {0,}, size[100] = {0,};
9648 if ((buffer = strstr(path, "ext="))) {
9649 buffer += strlen("ext=");
9651 if (strlen(buffer)) {
9652 strncpy(ext, buffer, 99);
9654 if ((seperator = strchr(ext, ','))
9655 || (seperator = strchr(ext, ' '))
9656 || (seperator = strchr(ext, '\0'))) {
9657 seperator[0] = '\0';
9662 if ((buffer = strstr(path, "size="))) {
9663 buffer += strlen("size=");
9665 if (strlen(buffer) > 0) {
9666 strncpy(size, buffer, 99);
9668 if ((seperator = strchr(size, ','))
9669 || (seperator = strchr(size, ' '))
9670 || (seperator = strchr(size, '\0'))) {
9671 seperator[0] = '\0';
9674 mem_size = atoi(size);
9679 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9681 if (mem_size && param) {
9682 if (data->input_mem.buf)
9683 free(data->input_mem.buf);
9684 data->input_mem.buf = malloc(mem_size);
9686 if (data->input_mem.buf) {
9687 memcpy(data->input_mem.buf, param, mem_size);
9688 data->input_mem.len = mem_size;
9689 ret = MM_ERROR_NONE;
9691 LOGE("failed to alloc mem %d", mem_size);
9692 ret = MM_ERROR_PLAYER_INTERNAL;
9695 data->input_mem.offset = 0;
9696 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9703 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9705 gchar *location = NULL;
9708 int ret = MM_ERROR_NONE;
9710 if ((path = strstr(uri, "file://"))) {
9711 location = g_filename_from_uri(uri, NULL, &err);
9712 if (!location || (err != NULL)) {
9713 LOGE("Invalid URI '%s' for filesrc: %s", path,
9714 (err != NULL) ? err->message : "unknown error");
9718 MMPLAYER_FREEIF(location);
9720 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9721 return MM_ERROR_PLAYER_INVALID_URI;
9723 LOGD("path from uri: %s", location);
9726 path = (location != NULL) ? (location) : ((char *)uri);
9729 ret = _mmplayer_exist_file_path(path);
9731 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9732 if (ret == MM_ERROR_NONE) {
9733 if (_mmplayer_is_sdp_file(path)) {
9734 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9735 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9736 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9738 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9739 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9741 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9742 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9744 LOGE("invalid uri, could not play..");
9745 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9748 MMPLAYER_FREEIF(location);
9753 static mmplayer_video_decoded_data_info_t *
9754 __mmplayer_create_stream_from_pad(GstPad *pad)
9756 GstCaps *caps = NULL;
9757 GstStructure *structure = NULL;
9758 unsigned int fourcc = 0;
9759 const gchar *string_format = NULL;
9760 mmplayer_video_decoded_data_info_t *stream = NULL;
9762 MMPixelFormatType format;
9765 caps = gst_pad_get_current_caps(pad);
9767 LOGE("Caps is NULL.");
9772 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9774 structure = gst_caps_get_structure(caps, 0);
9775 gst_structure_get_int(structure, "width", &width);
9776 gst_structure_get_int(structure, "height", &height);
9777 string_format = gst_structure_get_string(structure, "format");
9780 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9781 format = _mmplayer_get_pixtype(fourcc);
9782 gst_video_info_from_caps(&info, caps);
9783 gst_caps_unref(caps);
9786 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9787 LOGE("Wrong condition!!");
9791 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9793 LOGE("failed to alloc mem for video data");
9797 stream->width = width;
9798 stream->height = height;
9799 stream->format = format;
9800 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9806 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9808 unsigned int pitch = 0;
9809 unsigned int size = 0;
9811 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9814 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9815 bo = gst_tizen_memory_get_bos(mem, index);
9817 stream->bo[index] = tbm_bo_ref(bo);
9819 LOGE("failed to get bo for index %d", index);
9822 for (index = 0; index < stream->plane_num; index++) {
9823 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9824 stream->stride[index] = pitch;
9826 stream->elevation[index] = size / pitch;
9828 stream->elevation[index] = stream->height;
9833 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9835 if (stream->format == MM_PIXEL_FORMAT_I420) {
9836 int ret = TBM_SURFACE_ERROR_NONE;
9837 tbm_surface_h surface;
9838 tbm_surface_info_s info;
9840 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9842 ret = tbm_surface_get_info(surface, &info);
9843 if (ret != TBM_SURFACE_ERROR_NONE) {
9844 tbm_surface_destroy(surface);
9848 tbm_surface_destroy(surface);
9849 stream->stride[0] = info.planes[0].stride;
9850 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9851 stream->stride[1] = info.planes[1].stride;
9852 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9853 stream->stride[2] = info.planes[2].stride;
9854 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9855 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9856 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9857 stream->stride[0] = stream->width * 4;
9858 stream->elevation[0] = stream->height;
9859 stream->bo_size = stream->stride[0] * stream->height;
9861 LOGE("Not support format %d", stream->format);
9869 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9871 tbm_bo_handle thandle;
9873 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9874 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9875 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9879 unsigned char *src = NULL;
9880 unsigned char *dest = NULL;
9881 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9883 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9885 LOGE("fail to gst_memory_map");
9889 if (!mapinfo.data) {
9890 LOGE("data pointer is wrong");
9894 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9895 if (!stream->bo[0]) {
9896 LOGE("Fail to tbm_bo_alloc!!");
9900 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9902 LOGE("thandle pointer is wrong");
9906 if (stream->format == MM_PIXEL_FORMAT_I420) {
9907 src_stride[0] = GST_ROUND_UP_4(stream->width);
9908 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9909 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9910 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9913 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9914 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9916 for (i = 0; i < 3; i++) {
9917 src = mapinfo.data + src_offset[i];
9918 dest = thandle.ptr + dest_offset[i];
9923 for (j = 0; j < stream->height >> k; j++) {
9924 memcpy(dest, src, stream->width>>k);
9925 src += src_stride[i];
9926 dest += stream->stride[i];
9929 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9930 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9932 LOGE("Not support format %d", stream->format);
9936 tbm_bo_unmap(stream->bo[0]);
9937 gst_memory_unmap(mem, &mapinfo);
9943 tbm_bo_unmap(stream->bo[0]);
9946 gst_memory_unmap(mem, &mapinfo);
9952 __mmplayer_set_pause_state(mmplayer_t *player)
9954 if (player->sent_bos)
9957 /* rtsp case, get content attrs by GstMessage */
9958 if (MMPLAYER_IS_RTSP_STREAMING(player))
9961 /* it's first time to update all content attrs. */
9962 _mmplayer_update_content_attrs(player, ATTR_ALL);
9966 __mmplayer_set_playing_state(mmplayer_t *player)
9968 gchar *audio_codec = NULL;
9970 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9971 /* initialize because auto resume is done well. */
9972 player->resumed_by_rewind = FALSE;
9973 player->playback_rate = 1.0;
9976 if (player->sent_bos)
9979 /* try to get content metadata */
9981 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9982 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9983 * legacy mmfw-player api
9985 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9987 if ((player->cmd == MMPLAYER_COMMAND_START)
9988 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9989 __mmplayer_handle_missed_plugin(player);
9992 /* check audio codec field is set or not
9993 * we can get it from typefinder or codec's caps.
9995 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9997 /* The codec format can't be sent for audio only case like amr, mid etc.
9998 * Because, parser don't make related TAG.
9999 * So, if it's not set yet, fill it with found data.
10001 if (!audio_codec) {
10002 if (g_strrstr(player->type_caps_str, "audio/midi"))
10003 audio_codec = "MIDI";
10004 else if (g_strrstr(player->type_caps_str, "audio/x-amr"))
10005 audio_codec = "AMR";
10006 else if (g_strrstr(player->type_caps_str, "audio/mpeg")
10007 && !g_strrstr(player->type_caps_str, "mpegversion=(int)1"))
10008 audio_codec = "AAC";
10010 audio_codec = "unknown";
10012 if (mm_player_set_attribute((MMHandleType)player, NULL,
10013 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
10014 LOGE("failed to set attribute");
10016 LOGD("set audio codec type with caps");