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/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
87 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
91 count = gst_tag_list_get_tag_size(list, tag);
93 LOGD("count = %d", count);
95 for (i = 0; i < count; i++) {
98 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
99 if (!gst_tag_list_get_string_index(list, tag, i, &str))
100 g_assert_not_reached();
102 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
106 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
108 g_print(" : %s", str);
116 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
118 /* check whether the error is posted from not-activated track or not */
120 gint active_pad_index = 0;
122 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
124 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
125 LOGD("current active pad index -%d", active_pad_index);
127 if (src_element_name) {
130 if (player->audio_decoders) {
131 GList *adec = player->audio_decoders;
132 for (; adec ; adec = g_list_next(adec)) {
133 gchar *name = adec->data;
135 LOGD("found audio decoder name = %s", name);
136 if (g_strrstr(name, src_element_name)) {
143 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
146 if (active_pad_index != msg_src_pos) {
147 LOGD("skip error because error is posted from no activated track");
155 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
157 /* Demuxer can't parse one track because it's corrupted.
158 * So, the decoder for it is not linked.
159 * But, it has one playable track.
161 if (g_strrstr(klass, "Demux")) {
162 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
167 if (player->pipeline->audiobin) { // PCM
168 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
170 LOGD("not found any available codec. Player should be destroyed.");
171 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
176 return MM_ERROR_PLAYER_INVALID_STREAM;
180 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
182 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
183 LOGE("Not supported subtitle.");
184 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
186 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
190 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
192 /* Decoder Custom Message */
193 if (!strstr(error->message, "ongoing"))
194 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
196 if (strncasecmp(klass, "audio", 5)) {
197 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
198 LOGD("Video can keep playing.");
199 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
201 } else if (strncasecmp(klass, "video", 5)) {
202 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
203 LOGD("Audio can keep playing.");
204 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
208 LOGD("not found any available codec. Player should be destroyed.");
209 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
213 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
215 if (strstr(error->message, "rights expired"))
216 return MM_ERROR_PLAYER_DRM_EXPIRED;
217 else if (strstr(error->message, "no rights"))
218 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219 else if (strstr(error->message, "has future rights"))
220 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221 else if (strstr(error->message, "opl violation"))
222 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
224 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
227 /* NOTE : decide gstreamer state whether there is some playable track or not. */
229 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
231 gchar *src_element_name = NULL;
232 GstElement *src_element = NULL;
233 GstElementFactory *factory = NULL;
234 const gchar *klass = NULL;
238 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
239 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
240 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
241 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
243 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
245 src_element = GST_ELEMENT_CAST(message->src);
246 src_element_name = GST_ELEMENT_NAME(src_element);
247 if (!src_element_name)
248 return MM_ERROR_PLAYER_INTERNAL;
250 factory = gst_element_get_factory(src_element);
252 return MM_ERROR_PLAYER_INTERNAL;
254 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
256 return MM_ERROR_PLAYER_INTERNAL;
258 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
259 error->code, error->message, src_element_name, klass);
261 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
262 return MM_ERROR_NONE;
264 switch (error->code) {
265 case GST_STREAM_ERROR_DECODE:
266 return __mmplayer_gst_transform_error_decode(player, klass);
267 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
268 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
269 case GST_STREAM_ERROR_WRONG_TYPE:
270 return __mmplayer_gst_transform_error_type(player, src_element);
271 case GST_STREAM_ERROR_FAILED:
272 return __mmplayer_gst_transform_error_failed(player, klass, error);
273 case GST_STREAM_ERROR_DECRYPT:
274 case GST_STREAM_ERROR_DECRYPT_NOKEY:
275 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
276 return __mmplayer_gst_transform_error_decrypt(player, error);
283 return MM_ERROR_PLAYER_INVALID_STREAM;
287 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
289 gint trans_err = MM_ERROR_NONE;
293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
296 case GST_CORE_ERROR_MISSING_PLUGIN:
297 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
298 case GST_CORE_ERROR_STATE_CHANGE:
299 case GST_CORE_ERROR_SEEK:
300 case GST_CORE_ERROR_NOT_IMPLEMENTED:
301 case GST_CORE_ERROR_FAILED:
302 case GST_CORE_ERROR_TOO_LAZY:
303 case GST_CORE_ERROR_PAD:
304 case GST_CORE_ERROR_THREAD:
305 case GST_CORE_ERROR_NEGOTIATION:
306 case GST_CORE_ERROR_EVENT:
307 case GST_CORE_ERROR_CAPS:
308 case GST_CORE_ERROR_TAG:
309 case GST_CORE_ERROR_CLOCK:
310 case GST_CORE_ERROR_DISABLED:
312 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
322 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
324 gint trans_err = MM_ERROR_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
331 case GST_LIBRARY_ERROR_FAILED:
332 case GST_LIBRARY_ERROR_TOO_LAZY:
333 case GST_LIBRARY_ERROR_INIT:
334 case GST_LIBRARY_ERROR_SHUTDOWN:
335 case GST_LIBRARY_ERROR_SETTINGS:
336 case GST_LIBRARY_ERROR_ENCODE:
338 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
348 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
350 gint trans_err = MM_ERROR_NONE;
354 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
358 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
360 case GST_RESOURCE_ERROR_NOT_FOUND:
361 case GST_RESOURCE_ERROR_OPEN_READ:
362 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
363 || MMPLAYER_IS_RTSP_STREAMING(player)) {
364 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
367 case GST_RESOURCE_ERROR_READ:
368 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
369 || MMPLAYER_IS_RTSP_STREAMING(player)) {
370 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
372 } else if (message != NULL && message->src != NULL) {
373 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
374 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
376 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
377 path_type = MMPLAYER_PATH_VOD;
378 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
379 path_type = MMPLAYER_PATH_TEXT;
381 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
382 /* check storage state */
383 storage_get_state(player->storage_info[path_type].id, &storage_state);
384 player->storage_info[path_type].state = storage_state;
385 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
388 case GST_RESOURCE_ERROR_WRITE:
389 case GST_RESOURCE_ERROR_FAILED:
390 case GST_RESOURCE_ERROR_SEEK:
391 case GST_RESOURCE_ERROR_TOO_LAZY:
392 case GST_RESOURCE_ERROR_BUSY:
393 case GST_RESOURCE_ERROR_OPEN_WRITE:
394 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
395 case GST_RESOURCE_ERROR_CLOSE:
396 case GST_RESOURCE_ERROR_SYNC:
397 case GST_RESOURCE_ERROR_SETTINGS:
399 trans_err = MM_ERROR_PLAYER_INTERNAL;
409 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
411 gint trans_err = MM_ERROR_NONE;
415 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
416 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
417 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
419 switch (error->code) {
420 case GST_STREAM_ERROR_FAILED:
421 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
422 case GST_STREAM_ERROR_DECODE:
423 case GST_STREAM_ERROR_WRONG_TYPE:
424 case GST_STREAM_ERROR_DECRYPT:
425 case GST_STREAM_ERROR_DECRYPT_NOKEY:
426 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
427 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
430 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
431 case GST_STREAM_ERROR_TOO_LAZY:
432 case GST_STREAM_ERROR_ENCODE:
433 case GST_STREAM_ERROR_DEMUX:
434 case GST_STREAM_ERROR_MUX:
435 case GST_STREAM_ERROR_FORMAT:
437 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
447 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
449 MMMessageParamType msg_param;
450 gchar *msg_src_element;
454 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
455 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
457 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
459 memset(&msg_param, 0, sizeof(MMMessageParamType));
461 if (error->domain == GST_CORE_ERROR) {
462 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
463 } else if (error->domain == GST_LIBRARY_ERROR) {
464 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
465 } else if (error->domain == GST_RESOURCE_ERROR) {
466 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
467 } else if (error->domain == GST_STREAM_ERROR) {
468 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
470 LOGW("This error domain is not defined.");
472 /* we treat system error as an internal error */
473 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
477 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
479 msg_param.data = (void *)error->message;
481 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
482 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
486 if (msg_param.code == MM_ERROR_NONE)
489 /* skip error to avoid duplicated posting */
490 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
491 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
492 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
493 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
495 /* The error will be handled by mused.
496 * @ref _mmplayer_manage_external_storage_state() */
498 LOGW("storage is removed, skip error post");
502 /* post error to application */
503 if (!player->msg_posted) {
504 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
505 /* don't post more if one was sent already */
506 player->msg_posted = TRUE;
508 LOGD("skip error post because it's sent already.");
517 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
520 MMMessageParamType msg_param;
521 gchar *msg_src_element = NULL;
522 GstStructure *s = NULL;
524 gchar *error_string = NULL;
528 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
529 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
531 s = gst_structure_copy(gst_message_get_structure(message));
534 if (!gst_structure_get_uint(s, "error_id", &error_id))
535 error_id = MMPLAYER_STREAMING_ERROR_NONE;
538 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
539 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
541 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
542 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
544 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
545 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
547 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
548 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
550 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
551 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
553 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
554 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
556 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
557 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
559 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
560 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
562 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
563 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
565 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
566 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
568 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
569 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
571 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
572 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
574 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
575 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
577 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
578 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
580 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
581 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
583 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
584 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
586 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
587 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
589 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
590 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
592 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
593 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
595 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
596 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
598 case MMPLAYER_STREAMING_ERROR_GONE:
599 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
601 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
602 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
604 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
605 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
607 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
608 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
610 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
611 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
613 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
614 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
616 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
617 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
619 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
620 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
622 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
623 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
625 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
626 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
628 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
629 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
631 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
632 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
634 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
635 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
637 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
638 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
640 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
641 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
643 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
644 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
646 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
647 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
649 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
650 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
652 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
653 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
655 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
656 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
658 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
659 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
661 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
662 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
664 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
665 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
667 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
668 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
670 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
671 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
675 gst_structure_free(s);
676 return MM_ERROR_PLAYER_STREAMING_FAIL;
680 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
682 msg_param.data = (void *)error_string;
685 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
687 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
688 msg_src_element, msg_param.code, (char *)msg_param.data);
691 /* post error to application */
692 if (!player->msg_posted) {
693 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
695 /* don't post more if one was sent already */
696 player->msg_posted = TRUE;
698 LOGD("skip error post because it's sent already.");
701 gst_structure_free(s);
702 MMPLAYER_FREEIF(error_string);
710 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
712 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
713 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
714 gst_tag_list_get_string(tags, "stitching_software",
715 &metadata->stitching_software);
716 gst_tag_list_get_string(tags, "projection_type",
717 &metadata->projection_type_string);
718 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
719 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
720 gst_tag_list_get_int(tags, "init_view_heading",
721 &metadata->init_view_heading);
722 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
723 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
724 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
725 gst_tag_list_get_int(tags, "full_pano_width_pixels",
726 &metadata->full_pano_width_pixels);
727 gst_tag_list_get_int(tags, "full_pano_height_pixels",
728 &metadata->full_pano_height_pixels);
729 gst_tag_list_get_int(tags, "cropped_area_image_width",
730 &metadata->cropped_area_image_width);
731 gst_tag_list_get_int(tags, "cropped_area_image_height",
732 &metadata->cropped_area_image_height);
733 gst_tag_list_get_int(tags, "cropped_area_left",
734 &metadata->cropped_area_left);
735 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
736 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
737 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
738 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
742 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
745 /* macro for better code readability */
746 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
748 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
749 if (string != NULL) { \
750 SECURE_LOGD("update tag string : %s", string); \
751 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
752 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
753 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
754 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
755 mm_player_set_attribute((MMHandleType)player, NULL,\
756 playertag, new_string, strlen(new_string), NULL); \
757 MMPLAYER_FREEIF(new_string); \
759 mm_player_set_attribute((MMHandleType)player, NULL,\
760 playertag, string, strlen(string), NULL); \
762 MMPLAYER_FREEIF(string); \
767 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
769 GstSample *sample = NULL;\
770 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
771 GstMapInfo info = GST_MAP_INFO_INIT;\
772 buffer = gst_sample_get_buffer(sample);\
773 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
774 LOGD("failed to get image data from tag");\
775 gst_sample_unref(sample);\
778 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
779 MMPLAYER_FREEIF(player->album_art);\
780 player->album_art = (gchar *)g_malloc(info.size);\
781 if (player->album_art) {\
782 memcpy(player->album_art, info.data, info.size);\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, (void *)player->album_art, info.size, NULL); \
785 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
786 msg_param.data = (void *)player->album_art;\
787 msg_param.size = info.size;\
788 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
789 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
792 gst_buffer_unmap(buffer, &info);\
793 gst_sample_unref(sample);\
797 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
799 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
802 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
803 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
804 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
805 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
806 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
808 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
809 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
810 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
811 mm_player_set_attribute((MMHandleType)player, NULL,\
812 "content_audio_bitrate", v_uint, NULL); \
813 player->bitrate[track_type] = v_uint; \
814 player->total_bitrate = 0; \
815 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
816 player->total_bitrate += player->bitrate[i]; \
817 mm_player_set_attribute((MMHandleType)player, NULL,\
818 playertag, player->total_bitrate, NULL); \
819 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
820 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
821 player->maximum_bitrate[track_type] = v_uint; \
822 player->total_maximum_bitrate = 0; \
823 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
824 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
825 mm_player_set_attribute((MMHandleType)player, NULL,\
826 playertag, player->total_maximum_bitrate, NULL); \
827 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
829 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
836 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
838 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
840 string = g_strdup_printf("%d", g_date_get_year(date));\
841 mm_player_set_attribute((MMHandleType)player, NULL,\
842 playertag, string, strlen(string), NULL); \
843 SECURE_LOGD("metainfo year : %s", string);\
844 MMPLAYER_FREEIF(string);\
850 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
852 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
853 if (datetime != NULL) {\
854 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
855 mm_player_set_attribute((MMHandleType)player, NULL,\
856 playertag, string, strlen(string), NULL); \
857 SECURE_LOGD("metainfo year : %s", string);\
858 MMPLAYER_FREEIF(string);\
859 gst_date_time_unref(datetime);\
865 GstTagList *tag_list = NULL;
870 GstDateTime *datetime = NULL;
872 GstBuffer *buffer = NULL;
874 MMMessageParamType msg_param = {0, };
876 /* currently not used. but those are needed for above macro */
877 //guint64 v_uint64 = 0;
878 //gdouble v_double = 0;
880 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
882 /* get tag list from gst message */
883 gst_message_parse_tag(msg, &tag_list);
885 /* store tags to player attributes */
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
887 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
888 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
890 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
891 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
892 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
893 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
894 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
896 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
898 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
899 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
900 MMPLAYER_UPDATE_TAG_LOCK(player);
901 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
902 MMPLAYER_UPDATE_TAG_UNLOCK(player);
903 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
905 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
906 if (player->video360_metadata.is_spherical == -1) {
907 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
908 mm_player_set_attribute((MMHandleType)player, NULL,
909 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
910 if (player->video360_metadata.is_spherical == 1) {
911 LOGD("This is spherical content for 360 playback.");
912 player->is_content_spherical = TRUE;
914 LOGD("This is not spherical content");
915 player->is_content_spherical = FALSE;
918 if (player->video360_metadata.projection_type_string) {
919 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
920 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
922 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
923 player->is_content_spherical = player->is_video360_enabled = FALSE;
927 if (player->video360_metadata.stereo_mode_string) {
928 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
929 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
930 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
931 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
932 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
933 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
935 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
936 player->is_content_spherical = player->is_video360_enabled = FALSE;
942 gst_tag_list_unref(tag_list);
947 /* if retval is FALSE, it will be dropped for perfomance. */
949 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
951 gboolean retval = FALSE;
953 if (!(player->pipeline && player->pipeline->mainbin)) {
954 LOGE("player pipeline handle is null");
958 switch (GST_MESSAGE_TYPE(message)) {
959 case GST_MESSAGE_TAG:
960 case GST_MESSAGE_EOS:
961 case GST_MESSAGE_ERROR:
962 case GST_MESSAGE_WARNING:
963 case GST_MESSAGE_CLOCK_LOST:
964 case GST_MESSAGE_NEW_CLOCK:
965 case GST_MESSAGE_ELEMENT:
966 case GST_MESSAGE_DURATION_CHANGED:
967 case GST_MESSAGE_ASYNC_START:
968 case GST_MESSAGE_STREAM_COLLECTION:
971 case GST_MESSAGE_ASYNC_DONE:
972 case GST_MESSAGE_STATE_CHANGED:
973 /* we only handle messages from pipeline */
974 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
979 case GST_MESSAGE_BUFFERING:
981 gint buffer_percent = 0;
984 gst_message_parse_buffering(message, &buffer_percent);
985 if (buffer_percent != MAX_BUFFER_PERCENT) {
986 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
990 if (!MMPLAYER_CMD_TRYLOCK(player)) {
991 LOGW("can't get cmd lock, send msg to bus");
995 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
996 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
997 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1000 MMPLAYER_CMD_UNLOCK(player);
1004 case GST_MESSAGE_STREAMS_SELECTED:
1006 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1007 break; /* drop msg */
1009 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1010 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1011 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1013 gint64 dur_bytes = 0L;
1015 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1016 LOGE("fail to get duration.");
1018 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1019 * use file information was already set on Q2 when it was created. */
1020 _mm_player_streaming_set_queue2(player->streamer,
1021 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1022 TRUE, /* use_buffering */
1023 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1024 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1027 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1028 player->no_more_pad = TRUE;
1029 _mmplayer_pipeline_complete(NULL, player);
1042 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1044 guint64 data_size = 0;
1045 gint64 pos_nsec = 0;
1047 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1049 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1051 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1052 data_size = player->http_content_size;
1055 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1056 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1062 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1064 int ret = MM_ERROR_NONE;
1065 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1066 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1067 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1068 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1070 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1071 LOGW("do nothing for buffering msg");
1072 ret = MM_ERROR_PLAYER_INVALID_STATE;
1076 prev_state = MMPLAYER_PREV_STATE(player);
1077 current_state = MMPLAYER_CURRENT_STATE(player);
1078 target_state = MMPLAYER_TARGET_STATE(player);
1079 pending_state = MMPLAYER_PENDING_STATE(player);
1081 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1082 MMPLAYER_STATE_GET_NAME(prev_state),
1083 MMPLAYER_STATE_GET_NAME(current_state),
1084 MMPLAYER_STATE_GET_NAME(pending_state),
1085 MMPLAYER_STATE_GET_NAME(target_state),
1086 player->streamer->buffering_state);
1088 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1089 /* NOTE : if buffering has done, player has to go to target state. */
1090 switch (target_state) {
1091 case MM_PLAYER_STATE_PAUSED:
1093 switch (pending_state) {
1094 case MM_PLAYER_STATE_PLAYING:
1095 _mmplayer_gst_pause(player, TRUE);
1098 case MM_PLAYER_STATE_PAUSED:
1099 LOGD("player is already going to paused state, there is nothing to do.");
1102 case MM_PLAYER_STATE_NONE:
1103 case MM_PLAYER_STATE_NULL:
1104 case MM_PLAYER_STATE_READY:
1106 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1112 case MM_PLAYER_STATE_PLAYING:
1114 switch (pending_state) {
1115 case MM_PLAYER_STATE_NONE:
1117 if (current_state != MM_PLAYER_STATE_PLAYING)
1118 _mmplayer_gst_resume(player, TRUE);
1122 case MM_PLAYER_STATE_PAUSED:
1123 /* NOTE: It should be worked as asynchronously.
1124 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1126 if (current_state == MM_PLAYER_STATE_PLAYING) {
1127 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1128 * The current state should be changed to paused purposely to prevent state conflict.
1130 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1132 _mmplayer_gst_resume(player, TRUE);
1135 case MM_PLAYER_STATE_PLAYING:
1136 LOGD("player is already going to playing state, there is nothing to do.");
1139 case MM_PLAYER_STATE_NULL:
1140 case MM_PLAYER_STATE_READY:
1142 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1148 case MM_PLAYER_STATE_NULL:
1149 case MM_PLAYER_STATE_READY:
1150 case MM_PLAYER_STATE_NONE:
1152 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1156 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1157 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1159 switch (pending_state) {
1160 case MM_PLAYER_STATE_NONE:
1162 if (current_state != MM_PLAYER_STATE_PAUSED) {
1163 /* rtsp streaming pause makes rtsp server stop sending data. */
1164 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1165 LOGD("set pause state during buffering");
1166 _mmplayer_gst_pause(player, TRUE);
1172 case MM_PLAYER_STATE_PLAYING:
1173 /* rtsp streaming pause makes rtsp server stop sending data. */
1174 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1175 _mmplayer_gst_pause(player, TRUE);
1178 case MM_PLAYER_STATE_PAUSED:
1181 case MM_PLAYER_STATE_NULL:
1182 case MM_PLAYER_STATE_READY:
1184 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1193 static stream_variant_t *
1194 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1196 stream_variant_t *var_info = NULL;
1197 g_return_val_if_fail(self != NULL, NULL);
1199 var_info = g_new0(stream_variant_t, 1);
1200 if (!var_info) return NULL;
1201 var_info->bandwidth = self->bandwidth;
1202 var_info->width = self->width;
1203 var_info->height = self->height;
1208 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1214 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1215 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1217 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1218 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1219 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1221 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1222 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1223 player->http_content_size = (bytes > 0) ? bytes : 0;
1226 /* handling audio clip which has vbr. means duration is keep changing */
1227 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1236 __mmplayer_eos_timer_cb(gpointer u_data)
1238 mmplayer_t *player = NULL;
1239 MMHandleType attrs = 0;
1242 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1244 player = (mmplayer_t *)u_data;
1245 attrs = MMPLAYER_GET_ATTRS(player);
1247 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1251 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1252 if (ret_value != MM_ERROR_NONE)
1253 LOGE("seeking to 0 failed in repeat play");
1256 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1259 /* we are returning FALSE as we need only one posting */
1264 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1266 MMPLAYER_RETURN_IF_FAIL(player);
1268 /* post now if delay is zero */
1269 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1270 LOGD("eos delay is zero. posting EOS now");
1271 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1273 if (player->audio_decoded_cb)
1274 _mmplayer_cancel_eos_timer(player);
1279 /* cancel if existing */
1280 _mmplayer_cancel_eos_timer(player);
1282 /* init new timeout */
1283 /* NOTE : consider give high priority to this timer */
1284 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1286 player->eos_timer = g_timeout_add(delay_in_ms,
1287 __mmplayer_eos_timer_cb, player);
1289 player->context.global_default = g_main_context_default();
1290 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1292 /* check timer is valid. if not, send EOS now */
1293 if (player->eos_timer == 0) {
1294 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1295 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1300 __mmplayer_gst_pending_seek(mmplayer_t *player)
1302 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1303 int ret = MM_ERROR_NONE;
1307 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1309 if (!player->pending_seek.is_pending) {
1310 LOGD("pending seek is not reserved. nothing to do.");
1314 /* check player state if player could pending seek or not. */
1315 current_state = MMPLAYER_CURRENT_STATE(player);
1317 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1318 LOGW("try to pending seek in %s state, try next time. ",
1319 MMPLAYER_STATE_GET_NAME(current_state));
1323 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1325 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1326 if (ret != MM_ERROR_NONE)
1327 LOGE("failed to seek pending postion. just keep staying current position.");
1329 player->pending_seek.is_pending = false;
1337 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1339 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1341 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1343 audiobin = player->pipeline->audiobin; /* can be null */
1344 videobin = player->pipeline->videobin; /* can be null */
1345 textbin = player->pipeline->textbin; /* can be null */
1347 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1349 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1350 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1352 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1353 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1355 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1356 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1362 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1364 mmplayer_gst_element_t *textbin;
1367 MMPLAYER_RETURN_IF_FAIL(player &&
1369 player->pipeline->textbin);
1371 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1373 textbin = player->pipeline->textbin;
1376 LOGD("Drop subtitle text after getting EOS");
1378 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1379 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1381 player->is_subtitle_force_drop = TRUE;
1383 if (player->is_subtitle_force_drop == TRUE) {
1384 LOGD("Enable subtitle data path without drop");
1386 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1387 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1389 LOGD("non-connected with external display");
1391 player->is_subtitle_force_drop = FALSE;
1397 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1399 MMHandleType attrs = 0;
1404 /* NOTE : EOS event is comming multiple time. watch out it */
1405 /* check state. we only process EOS when pipeline state goes to PLAYING */
1406 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1407 LOGD("EOS received on non-playing state. ignoring it");
1411 if (player->pipeline && player->pipeline->textbin)
1412 __mmplayer_drop_subtitle(player, TRUE);
1414 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1415 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1417 /* rewind if repeat count is greater then zero */
1418 /* get play count */
1419 attrs = MMPLAYER_GET_ATTRS(player);
1421 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1423 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1425 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1426 if (player->playback_rate < 0.0) {
1427 player->resumed_by_rewind = TRUE;
1428 _mmplayer_set_mute((MMHandleType)player, false);
1429 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1432 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1435 player->sent_bos = FALSE;
1437 LOGD("do not post eos msg for repeating");
1442 if (player->pipeline)
1443 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1445 /* post eos message to application */
1446 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1448 /* reset last position */
1449 player->last_position = 0;
1456 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1458 GError *error = NULL;
1459 gchar *debug = NULL;
1463 /* generating debug info before returning error */
1464 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1466 /* get error code */
1467 gst_message_parse_error(msg, &error, &debug);
1469 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1470 /* Note : the streaming error from the streaming source is handled
1471 * using __mmplayer_handle_streaming_error.
1473 __mmplayer_handle_streaming_error(player, msg);
1475 /* dump state of all element */
1476 _mmplayer_dump_pipeline_state(player);
1478 /* traslate gst error code to msl error code. then post it
1479 * to application if needed
1481 __mmplayer_handle_gst_error(player, msg, error);
1484 LOGE("error debug : %s", debug);
1487 MMPLAYER_FREEIF(debug);
1488 g_error_free(error);
1495 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1497 MMMessageParamType msg_param = {0, };
1498 int bRet = MM_ERROR_NONE;
1501 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1503 if (!MMPLAYER_IS_STREAMING(player)) {
1504 LOGW("this is not streaming playback.");
1508 MMPLAYER_CMD_LOCK(player);
1510 if (!player->streamer) {
1511 LOGW("Pipeline is shutting down");
1512 MMPLAYER_CMD_UNLOCK(player);
1516 /* ignore the remained buffering message till getting 100% msg */
1517 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1518 gint buffer_percent = 0;
1520 gst_message_parse_buffering(msg, &buffer_percent);
1522 if (buffer_percent == MAX_BUFFER_PERCENT) {
1523 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1524 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1525 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1527 MMPLAYER_CMD_UNLOCK(player);
1531 /* ignore the remained buffering message */
1532 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1533 gint buffer_percent = 0;
1535 gst_message_parse_buffering(msg, &buffer_percent);
1537 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1538 player->streamer->buffering_percent, buffer_percent);
1540 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1541 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1542 player->streamer->buffering_req.is_pre_buffering = FALSE;
1544 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1546 LOGD("interrupted buffering - ignored the remained buffering msg!");
1547 MMPLAYER_CMD_UNLOCK(player);
1552 __mmplayer_update_buffer_setting(player, msg);
1554 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1556 if (bRet == MM_ERROR_NONE) {
1557 msg_param.connection.buffering = player->streamer->buffering_percent;
1558 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1560 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1561 player->pending_resume &&
1562 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1564 player->is_external_subtitle_added_now = FALSE;
1565 player->pending_resume = FALSE;
1566 _mmplayer_resume((MMHandleType)player);
1569 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1570 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1572 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1573 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1574 player->seek_state = MMPLAYER_SEEK_NONE;
1575 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1576 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1577 /* Considering the async state trasition in case of RTSP.
1578 After getting state change gst msg, seek cmpleted msg will be posted. */
1579 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1583 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1584 if (!player->streamer) {
1585 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1586 MMPLAYER_CMD_UNLOCK(player);
1590 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1592 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1593 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1595 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1596 msg_param.connection.buffering = player->streamer->buffering_percent;
1597 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1599 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1602 msg_param.connection.buffering = player->streamer->buffering_percent;
1603 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1606 MMPLAYER_CMD_UNLOCK(player);
1614 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1616 mmplayer_gst_element_t *mainbin;
1617 const GValue *voldstate, *vnewstate, *vpending;
1618 GstState oldstate = GST_STATE_NULL;
1619 GstState newstate = GST_STATE_NULL;
1620 GstState pending = GST_STATE_NULL;
1623 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1625 mainbin = player->pipeline->mainbin;
1627 /* we only handle messages from pipeline */
1628 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1631 /* get state info from msg */
1632 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1633 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1634 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1636 if (!voldstate || !vnewstate) {
1637 LOGE("received msg has wrong format.");
1641 oldstate = (GstState)voldstate->data[0].v_int;
1642 newstate = (GstState)vnewstate->data[0].v_int;
1644 pending = (GstState)vpending->data[0].v_int;
1646 LOGD("state changed [%s] : %s ---> %s final : %s",
1647 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1648 gst_element_state_get_name((GstState)oldstate),
1649 gst_element_state_get_name((GstState)newstate),
1650 gst_element_state_get_name((GstState)pending));
1652 if (newstate == GST_STATE_PLAYING) {
1653 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1655 int retVal = MM_ERROR_NONE;
1656 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1658 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1660 if (MM_ERROR_NONE != retVal)
1661 LOGE("failed to seek pending postion. just keep staying current position.");
1663 player->pending_seek.is_pending = false;
1667 if (oldstate == newstate) {
1668 LOGD("pipeline reports state transition to old state");
1673 case GST_STATE_PAUSED:
1675 gboolean prepare_async = FALSE;
1677 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1678 // managed prepare async case
1679 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1680 LOGD("checking prepare mode for async transition - %d", prepare_async);
1683 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1684 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1686 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1687 _mm_player_streaming_set_content_bitrate(player->streamer,
1688 player->total_maximum_bitrate, player->total_bitrate);
1690 if (player->pending_seek.is_pending) {
1691 LOGW("trying to do pending seek");
1692 MMPLAYER_CMD_LOCK(player);
1693 __mmplayer_gst_pending_seek(player);
1694 MMPLAYER_CMD_UNLOCK(player);
1700 case GST_STATE_PLAYING:
1702 if (MMPLAYER_IS_STREAMING(player)) {
1703 // managed prepare async case when buffering is completed
1704 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1705 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1706 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1707 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1709 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1711 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1712 if (player->streamer->buffering_percent < 100) {
1714 MMMessageParamType msg_param = {0, };
1715 LOGW("Posting Buffering Completed Message to Application !!!");
1717 msg_param.connection.buffering = 100;
1718 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1723 if (player->gapless.stream_changed) {
1724 _mmplayer_update_content_attrs(player, ATTR_ALL);
1725 player->gapless.stream_changed = FALSE;
1728 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1729 player->seek_state = MMPLAYER_SEEK_NONE;
1730 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1734 case GST_STATE_VOID_PENDING:
1735 case GST_STATE_NULL:
1736 case GST_STATE_READY:
1746 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1748 const gchar *structure_name;
1749 gint count = 0, idx = 0;
1752 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1754 if (gst_message_get_structure(msg) == NULL)
1757 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1758 if (!structure_name)
1761 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1763 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1764 const GValue *var_info = NULL;
1766 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1767 if (var_info != NULL) {
1768 if (player->adaptive_info.var_list)
1769 g_list_free_full(player->adaptive_info.var_list, g_free);
1771 /* share addr or copy the list */
1772 player->adaptive_info.var_list =
1773 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1775 count = g_list_length(player->adaptive_info.var_list);
1777 stream_variant_t *temp = NULL;
1779 /* print out for debug */
1780 LOGD("num of variant_info %d", count);
1781 for (idx = 0; idx < count; idx++) {
1782 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1784 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1790 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1791 gint num_buffers = 0;
1792 gint extra_num_buffers = 0;
1794 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1795 LOGD("video_num_buffers : %d", num_buffers);
1796 mm_player_set_attribute((MMHandleType)player, NULL,
1797 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1800 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1801 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1802 mm_player_set_attribute((MMHandleType)player, NULL,
1803 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1808 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1809 _mmplayer_track_update_text_attr_info(player, msg);
1811 /* custom message */
1812 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1813 MMMessageParamType msg_param = {0,};
1814 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1815 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1818 /* custom message for RTSP attribute :
1819 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1820 sdp which has contents info is received when rtsp connection is opened.
1821 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1822 if (!strcmp(structure_name, "rtspsrc_properties")) {
1823 gchar *audio_codec = NULL;
1824 gchar *video_codec = NULL;
1825 gchar *video_frame_size = NULL;
1827 gst_structure_get(gst_message_get_structure(msg),
1828 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1829 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1830 player->streaming_type = _mmplayer_get_stream_service_type(player);
1832 gst_structure_get(gst_message_get_structure(msg),
1833 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1834 LOGD("rtsp_audio_codec : %s", audio_codec);
1836 mm_player_set_attribute((MMHandleType)player, NULL,
1837 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1839 gst_structure_get(gst_message_get_structure(msg),
1840 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1841 LOGD("rtsp_video_codec : %s", video_codec);
1843 mm_player_set_attribute((MMHandleType)player, NULL,
1844 "content_video_codec", video_codec, strlen(video_codec), NULL);
1846 gst_structure_get(gst_message_get_structure(msg),
1847 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1848 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1849 if (video_frame_size) {
1850 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1851 mm_player_set_attribute((MMHandleType)player, NULL,
1852 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1853 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1855 g_strfreev(res_str);
1864 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1866 mmplayer_gst_element_t *mainbin;
1869 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1871 mainbin = player->pipeline->mainbin;
1873 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1875 /* we only handle messages from pipeline */
1876 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1879 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1880 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1881 player->seek_state = MMPLAYER_SEEK_NONE;
1882 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1883 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1884 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1885 LOGD("sync %s state(%s) with parent state(%s)",
1886 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1887 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1888 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1890 /* In case of streaming, pause is required before finishing seeking by buffering.
1891 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1892 Because the buffering state is controlled according to the state transition for force resume,
1893 the decodebin state should be paused as player state. */
1894 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1897 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1898 (player->streamer) &&
1899 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1900 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1901 GstQuery *query = NULL;
1902 gboolean busy = FALSE;
1905 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1906 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1907 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1908 gst_query_parse_buffering_percent(query, &busy, &percent);
1909 gst_query_unref(query);
1911 LOGD("buffered percent(%s): %d",
1912 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1916 __mmplayer_handle_buffering_playback(player);
1919 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1928 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1930 GValue val = { 0, };
1932 gint depth = GPOINTER_TO_INT(user_data);
1934 if (!gst_tag_list_copy_value(&val, tags, tag))
1937 if (G_VALUE_HOLDS_STRING(&val))
1938 str = g_value_dup_string(&val);
1940 str = gst_value_serialize(&val);
1942 LOGD("%*s%s: %s\n", 2 * depth, " ", gst_tag_get_nick(tag), str);
1944 g_value_unset(&val);
1948 __mmplayer_dump_collection(GstStreamCollection * collection)
1951 GstTagList *tags = NULL;
1952 GstCaps *caps = NULL;
1954 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1955 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1956 LOGD ("collection: Stream %u type %s flags 0x%x\n", i,
1957 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1958 gst_stream_get_stream_flags(stream));
1959 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1961 caps = gst_stream_get_caps(stream);
1963 gchar *caps_str = gst_caps_to_string(caps);
1964 LOGD (" caps: %s\n", caps_str);
1966 gst_caps_unref(caps);
1969 tags = gst_stream_get_tags(stream);
1972 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(3));
1973 gst_tag_list_unref(tags);
1979 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1980 GstStream *stream, GParamSpec *pspec, gpointer data)
1983 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1984 stream->stream_id, pspec->name, collection);
1985 if (g_str_equal(pspec->name, "caps")) {
1986 GstCaps *caps = gst_stream_get_caps(stream);
1987 gchar *caps_str = gst_caps_to_string(caps);
1988 LOGD (" New caps: %s\n", caps_str);
1990 gst_caps_unref(caps);
1995 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1997 mmplayer_t *player = (mmplayer_t *)(data);
1999 MMPLAYER_RETURN_IF_FAIL(player);
2000 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2002 switch (GST_MESSAGE_TYPE(msg)) {
2003 case GST_MESSAGE_UNKNOWN:
2004 LOGD("unknown message received");
2007 case GST_MESSAGE_EOS:
2008 LOGD("GST_MESSAGE_EOS received");
2009 __mmplayer_gst_handle_eos_message(player, msg);
2012 case GST_MESSAGE_ERROR:
2013 _mmplayer_set_reconfigure_state(player, FALSE);
2014 __mmplayer_gst_handle_error_message(player, msg);
2017 case GST_MESSAGE_WARNING:
2020 GError *error = NULL;
2022 gst_message_parse_warning(msg, &error, &debug);
2024 LOGD("warning : %s", error->message);
2025 LOGD("debug : %s", debug);
2027 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2029 MMPLAYER_FREEIF(debug);
2030 g_error_free(error);
2034 case GST_MESSAGE_TAG:
2036 LOGD("GST_MESSAGE_TAG");
2037 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2038 LOGW("failed to extract tags from gstmessage");
2042 case GST_MESSAGE_BUFFERING:
2043 __mmplayer_gst_handle_buffering_message(player, msg);
2046 case GST_MESSAGE_STATE_CHANGED:
2047 __mmplayer_gst_handle_state_message(player, msg);
2050 case GST_MESSAGE_CLOCK_LOST:
2052 GstClock *clock = NULL;
2053 gboolean need_new_clock = FALSE;
2055 gst_message_parse_clock_lost(msg, &clock);
2056 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2058 if (!player->videodec_linked)
2059 need_new_clock = TRUE;
2060 else if (!player->ini.use_system_clock)
2061 need_new_clock = TRUE;
2063 if (need_new_clock) {
2064 LOGD("Provide clock is TRUE, do pause->resume");
2065 _mmplayer_gst_pause(player, FALSE);
2066 _mmplayer_gst_resume(player, FALSE);
2071 case GST_MESSAGE_NEW_CLOCK:
2073 GstClock *clock = NULL;
2074 gst_message_parse_new_clock(msg, &clock);
2075 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2079 case GST_MESSAGE_ELEMENT:
2080 __mmplayer_gst_handle_element_message(player, msg);
2083 case GST_MESSAGE_DURATION_CHANGED:
2085 LOGD("GST_MESSAGE_DURATION_CHANGED");
2086 if (!__mmplayer_gst_handle_duration(player, msg))
2087 LOGW("failed to update duration");
2091 case GST_MESSAGE_ASYNC_START:
2092 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2095 case GST_MESSAGE_ASYNC_DONE:
2096 __mmplayer_gst_handle_async_done_message(player, msg);
2098 case GST_MESSAGE_STREAM_COLLECTION:
2100 GstStreamCollection *collection = NULL;
2101 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2103 gst_message_parse_stream_collection(msg, &collection);
2105 __mmplayer_dump_collection(collection);
2106 if (player->collection && player->stream_notify_id) {
2107 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2108 player->stream_notify_id = 0;
2110 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2111 if (player->collection) {
2112 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2113 (GCallback)__mmplayer_stream_notify_cb, player);
2115 gst_object_unref(collection);
2118 case GST_MESSAGE_STREAMS_SELECTED:
2120 GstStreamCollection *collection = NULL;
2121 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2123 gst_message_parse_streams_selected(msg, &collection);
2125 guint i = 0, len = 0;
2126 len = gst_message_streams_selected_get_size(msg);
2127 for (i = 0; i < len; i++) {
2128 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2129 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2130 gst_object_unref(stream);
2132 gst_object_unref (collection);
2137 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2138 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2139 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2140 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2141 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2142 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2143 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2144 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2145 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2146 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2147 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2148 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2149 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2150 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2151 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2158 /* should not call 'gst_message_unref(msg)' */
2162 static GstBusSyncReply
2163 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2165 mmplayer_t *player = (mmplayer_t *)data;
2166 GstBusSyncReply reply = GST_BUS_DROP;
2168 if (!(player->pipeline && player->pipeline->mainbin)) {
2169 LOGE("player pipeline handle is null");
2170 return GST_BUS_PASS;
2173 if (!__mmplayer_gst_check_useful_message(player, message)) {
2174 gst_message_unref(message);
2175 return GST_BUS_DROP;
2178 switch (GST_MESSAGE_TYPE(message)) {
2179 case GST_MESSAGE_TAG:
2180 __mmplayer_gst_extract_tag_from_msg(player, message);
2184 GstTagList *tags = NULL;
2186 gst_message_parse_tag(message, &tags);
2188 LOGE("TAGS received from element \"%s\".",
2189 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2191 gst_tag_list_foreach(tags, print_tag, NULL);
2192 gst_tag_list_unref(tags);
2200 case GST_MESSAGE_DURATION_CHANGED:
2201 __mmplayer_gst_handle_duration(player, message);
2203 case GST_MESSAGE_ELEMENT:
2205 const gchar *klass = NULL;
2206 klass = gst_element_factory_get_metadata
2207 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2208 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2209 reply = GST_BUS_PASS;
2212 __mmplayer_gst_handle_element_message(player, message);
2215 case GST_MESSAGE_ASYNC_DONE:
2216 /* NOTE:Don't call gst_callback directly
2217 * because previous frame can be showed even though this message is received for seek.
2220 reply = GST_BUS_PASS;
2224 if (reply == GST_BUS_DROP)
2225 gst_message_unref(message);
2231 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2233 GstElement *appsrc = element;
2234 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2235 GstBuffer *buffer = NULL;
2236 GstFlowReturn ret = GST_FLOW_OK;
2239 MMPLAYER_RETURN_IF_FAIL(element);
2240 MMPLAYER_RETURN_IF_FAIL(buf);
2242 buffer = gst_buffer_new();
2244 if (buf->offset < 0 || buf->len < 0) {
2245 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2249 if (buf->offset >= buf->len) {
2250 LOGD("call eos appsrc");
2251 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2255 if (buf->len - buf->offset < size)
2256 len = buf->len - buf->offset;
2258 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2259 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2260 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2263 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2265 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2271 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2273 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2275 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2277 buf->offset = (int)size;
2283 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2285 mmplayer_t *player = (mmplayer_t *)user_data;
2286 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2287 MMMessageParamType msg_param = {0,};
2288 guint64 current_level_bytes = 0;
2290 MMPLAYER_RETURN_IF_FAIL(player);
2292 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2293 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2294 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2295 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2297 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2301 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2303 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2305 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2306 msg_param.buffer_status.stream_type = stream_type;
2307 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2308 msg_param.buffer_status.bytes = current_level_bytes;
2310 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2314 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2316 mmplayer_t *player = (mmplayer_t *)user_data;
2317 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2318 MMMessageParamType msg_param = {0,};
2319 guint64 current_level_bytes = 0;
2321 MMPLAYER_RETURN_IF_FAIL(player);
2323 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2324 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2325 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2326 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2328 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2332 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2334 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2336 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2337 msg_param.buffer_status.stream_type = stream_type;
2338 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2339 msg_param.buffer_status.bytes = current_level_bytes;
2341 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2345 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2347 mmplayer_t *player = (mmplayer_t *)user_data;
2348 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2349 MMMessageParamType msg_param = {0,};
2351 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2353 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2354 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2355 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2356 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2358 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2362 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2364 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2365 msg_param.seek_data.stream_type = stream_type;
2366 msg_param.seek_data.offset = position;
2368 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2374 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2376 #define MAX_LEN_NAME 20
2378 gboolean ret = FALSE;
2379 GstPad *sinkpad = NULL;
2380 gchar *prefix = NULL;
2381 gchar dec_name[MAX_LEN_NAME] = {0, };
2382 main_element_id_e elem_id = MMPLAYER_M_NUM;
2384 mmplayer_gst_element_t *mainbin = NULL;
2385 GstElement *decodebin = NULL;
2386 GstCaps *dec_caps = NULL;
2390 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2392 player->pipeline->mainbin, FALSE);
2393 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2395 mainbin = player->pipeline->mainbin;
2397 case MM_PLAYER_STREAM_TYPE_AUDIO:
2399 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2401 case MM_PLAYER_STREAM_TYPE_VIDEO:
2403 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2406 LOGE("invalid type %d", type);
2410 if (mainbin[elem_id].gst) {
2411 LOGE("elem(%d) is already created", elem_id);
2415 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2417 /* create decodebin */
2418 decodebin = gst_element_factory_make("decodebin", dec_name);
2420 LOGE("failed to create %s", dec_name);
2424 mainbin[elem_id].id = elem_id;
2425 mainbin[elem_id].gst = decodebin;
2427 /* raw pad handling signal */
2428 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2429 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2431 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2432 before looking for any elements that can handle that stream.*/
2433 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2434 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2436 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2437 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2438 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2440 /* This signal is emitted when a element is added to the bin.*/
2441 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2442 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2444 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2445 LOGE("failed to add new decodebin");
2449 dec_caps = gst_pad_query_caps(srcpad, NULL);
2452 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2454 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2455 gst_caps_unref(dec_caps);
2458 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2460 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2461 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2464 gst_object_unref(GST_OBJECT(sinkpad));
2466 gst_element_sync_state_with_parent(decodebin);
2472 gst_object_unref(GST_OBJECT(sinkpad));
2474 if (mainbin[elem_id].gst) {
2475 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2476 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2477 gst_object_unref(mainbin[elem_id].gst);
2478 mainbin[elem_id].gst = NULL;
2486 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2488 #define MAX_LEN_NAME 20
2489 mmplayer_gst_element_t *mainbin = NULL;
2490 gchar *prefix = NULL;
2491 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2493 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2494 GstElement *src = NULL, *queue = NULL;
2495 GstPad *srcpad = NULL;
2498 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2499 player->pipeline->mainbin, FALSE);
2501 mainbin = player->pipeline->mainbin;
2503 LOGD("type(%d) path is creating", type);
2505 case MM_PLAYER_STREAM_TYPE_AUDIO:
2507 if (mainbin[MMPLAYER_M_SRC].gst)
2508 src_id = MMPLAYER_M_2ND_SRC;
2510 src_id = MMPLAYER_M_SRC;
2511 queue_id = MMPLAYER_M_A_BUFFER;
2513 case MM_PLAYER_STREAM_TYPE_VIDEO:
2515 src_id = MMPLAYER_M_SRC;
2516 queue_id = MMPLAYER_M_V_BUFFER;
2518 case MM_PLAYER_STREAM_TYPE_TEXT:
2519 prefix = "subtitle";
2520 src_id = MMPLAYER_M_SUBSRC;
2521 queue_id = MMPLAYER_M_S_BUFFER;
2524 LOGE("invalid type %d", type);
2528 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2529 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2532 src = gst_element_factory_make("appsrc", src_name);
2534 LOGF("failed to create %s", src_name);
2538 mainbin[src_id].id = src_id;
2539 mainbin[src_id].gst = src;
2541 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2542 "caps", caps, NULL);
2544 /* size of many video frames are larger than default blocksize as 4096 */
2545 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2546 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2548 if (player->media_stream_buffer_max_size[type] > 0)
2549 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2551 if (player->media_stream_buffer_min_percent[type] > 0)
2552 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2554 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2555 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2557 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2558 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2559 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2560 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2561 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2562 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2565 queue = gst_element_factory_make("queue2", queue_name);
2567 LOGE("failed to create %s", queue_name);
2570 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2572 mainbin[queue_id].id = queue_id;
2573 mainbin[queue_id].gst = queue;
2575 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2576 LOGE("failed to add src");
2580 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2581 LOGE("failed to add queue");
2585 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2586 LOGE("failed to link src and queue");
2590 /* create decoder */
2591 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2593 LOGE("failed to get srcpad of queue");
2597 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2598 _mmplayer_gst_create_decoder(player, srcpad, caps);
2600 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2601 LOGE("failed to create decoder");
2602 gst_object_unref(GST_OBJECT(srcpad));
2606 gst_object_unref(GST_OBJECT(srcpad));
2610 if (mainbin[src_id].gst) {
2611 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2612 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2613 gst_object_unref(mainbin[src_id].gst);
2614 mainbin[src_id].gst = NULL;
2617 if (mainbin[queue_id].gst) {
2618 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2619 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2620 gst_object_unref(mainbin[queue_id].gst);
2621 mainbin[queue_id].gst = NULL;
2628 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2630 GstPad *sinkpad = NULL;
2631 GstCaps *caps = NULL;
2632 GstElement *new_element = NULL;
2633 GstStructure *str = NULL;
2634 const gchar *name = NULL;
2636 mmplayer_t *player = (mmplayer_t *)data;
2640 MMPLAYER_RETURN_IF_FAIL(element && pad);
2641 MMPLAYER_RETURN_IF_FAIL(player &&
2643 player->pipeline->mainbin);
2645 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2646 * num_dynamic_pad will decreased after creating a sinkbin.
2648 player->num_dynamic_pad++;
2649 LOGD("stream count inc : %d", player->num_dynamic_pad);
2651 caps = gst_pad_query_caps(pad, NULL);
2652 MMPLAYER_CHECK_NULL(caps);
2654 str = gst_caps_get_structure(caps, 0);
2655 name = gst_structure_get_string(str, "media");
2657 LOGE("cannot get mimetype from structure.");
2661 if (strstr(name, "video")) {
2663 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2665 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2666 if (player->v_stream_caps) {
2667 gst_caps_unref(player->v_stream_caps);
2668 player->v_stream_caps = NULL;
2671 new_element = gst_element_factory_make("fakesink", NULL);
2672 player->num_dynamic_pad--;
2677 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2678 LOGE("failed to autoplug for caps");
2682 gst_caps_unref(caps);
2687 /* excute new_element if created*/
2689 LOGD("adding new element to pipeline");
2691 /* set state to READY before add to bin */
2692 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2694 /* add new element to the pipeline */
2695 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2696 LOGE("failed to add autoplug element to bin");
2700 /* get pad from element */
2701 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2703 LOGE("failed to get sinkpad from autoplug element");
2708 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2709 LOGE("failed to link autoplug element");
2713 gst_object_unref(sinkpad);
2716 /* run. setting PLAYING here since streamming source is live source */
2717 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2721 gst_caps_unref(caps);
2727 STATE_CHANGE_FAILED:
2729 /* FIXIT : take care if new_element has already added to pipeline */
2731 gst_object_unref(GST_OBJECT(new_element));
2734 gst_object_unref(GST_OBJECT(sinkpad));
2737 gst_caps_unref(caps);
2739 /* FIXIT : how to inform this error to MSL ????? */
2740 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2741 * then post an error to application
2746 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2748 mmplayer_t *player = (mmplayer_t *)data;
2752 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2753 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2754 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2755 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2757 * [1] audio and video will be dumped with filesink.
2758 * [2] autoplugging is done by just using pad caps.
2759 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2760 * and the video will be dumped via filesink.
2762 if (player->num_dynamic_pad == 0) {
2763 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2765 if (!_mmplayer_gst_remove_fakesink(player,
2766 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2767 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2768 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2769 * source element are not same. To overcome this situation, this function will called
2770 * several places and several times. Therefore, this is not an error case.
2775 /* create dot before error-return. for debugging */
2776 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2778 player->no_more_pad = TRUE;
2784 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2786 GstElement *element = NULL;
2787 gchar *user_agent = NULL;
2788 MMHandleType attrs = 0;
2791 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2793 /* get profile attribute */
2794 attrs = MMPLAYER_GET_ATTRS(player);
2796 LOGE("failed to get content attribute");
2800 element = gst_element_factory_make("rtspsrc", "rtsp source");
2802 LOGE("failed to create rtspsrc element");
2807 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2809 SECURE_LOGD("user_agent : %s", user_agent);
2811 /* setting property to streaming source */
2812 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2814 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2816 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2817 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2818 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2819 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2825 void __mmplayer_http_src_setup(GstElement *element, GstElement *source, gpointer data)
2827 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2829 mmplayer_t *player = (mmplayer_t *)data;
2830 MMHandleType attrs = 0;
2831 gchar *user_agent, *cookies, **cookie_list;
2832 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2833 user_agent = cookies = NULL;
2837 MMPLAYER_RETURN_IF_FAIL(player);
2839 LOGD("source element %s", GST_ELEMENT_NAME(source));
2841 /* get profile attribute */
2842 attrs = MMPLAYER_GET_ATTRS(player);
2844 LOGE("failed to get content attribute");
2849 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2850 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2852 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2853 http_timeout = player->ini.http_timeout;
2856 SECURE_LOGD("cookies : %s", cookies);
2857 SECURE_LOGD("user_agent : %s", user_agent);
2858 LOGD("timeout : %d", http_timeout);
2860 /* setting property to streaming source */
2861 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2863 /* parsing cookies */
2864 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2865 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2866 g_strfreev(cookie_list);
2870 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2877 __mmplayer_source_setup_cb(GstElement *element, GstElement *source, gpointer data)
2879 mmplayer_t *player = (mmplayer_t *)data;
2880 LOGD("%s >> %s", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(source));
2882 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2883 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2885 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2886 __mmplayer_http_src_setup(element, source, data);
2887 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2888 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2892 gint __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2893 GstStream * stream, gpointer data)
2895 GstStreamType stype = gst_stream_get_stream_type (stream);
2897 if (stype & GST_STREAM_TYPE_AUDIO)
2898 LOGW("AUDIO type 0x%X", stype);
2899 else if (stype & GST_STREAM_TYPE_VIDEO)
2900 LOGW("VIDEO type 0x%X", stype);
2901 else if (stype & GST_STREAM_TYPE_TEXT)
2902 LOGW("TEXT type 0x%X", stype);
2908 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2910 gchar *factory_name = NULL;
2911 mmplayer_t *player = (mmplayer_t *)data;
2912 mmplayer_gst_element_t *mainbin = NULL;
2915 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2917 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
2918 mainbin = player->pipeline->mainbin;
2920 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
2921 factory_name, GST_ELEMENT_NAME(element));
2923 /* keep the first typefind reference only */
2924 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+
2925 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
2926 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
2928 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2929 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
2930 LOGD("typefind reference is added");
2934 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst && g_strrstr(factory_name, "queue2")) { // fix me :streaming only..
2936 gint64 dur_bytes = 0L;
2937 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
2939 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
2940 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
2942 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
2943 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
2945 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
2947 /* NOTE : in case of ts streaming, player could not get the correct duration info *
2948 * skip the pull mode(file or ring buffering) setting. */
2949 if (dur_bytes > 0) {
2950 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
2951 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
2952 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
2958 _mm_player_streaming_set_queue2(player->streamer,
2962 (guint64)dur_bytes); /* no meaning at the moment */
2967 if (g_strrstr(factory_name, "parsebin")) {
2968 if (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
2969 GstIterator *iter = NULL;
2970 GValue item = {0, };
2971 GstElement *ch_element = NULL;
2972 GstElementFactory *ch_factory = NULL;
2974 iter = gst_bin_iterate_recurse(child);
2976 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
2977 ch_element = g_value_get_object(&item);
2978 ch_factory = gst_element_get_factory(ch_element);
2980 if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) {
2981 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
2982 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
2984 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
2985 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
2986 (MMPLAYER_IS_DASH_STREAMING(player))) {
2987 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
2989 g_value_reset(&item);
2992 g_value_reset(&item);
2994 gst_iterator_free(iter);
2999 if (g_strrstr(factory_name, "parsebin")) {
3001 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3002 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3004 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3005 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3006 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3007 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3009 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3010 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3012 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
3013 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3014 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort", G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
3016 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3017 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3020 _mmplayer_gst_element_added((GstElement *)child, element, data);
3026 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3028 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3033 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3035 GstElement *uridecodebin3 = NULL;
3038 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3040 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3041 if (!uridecodebin3) {
3042 LOGE("failed to create uridecodebin3");
3047 SECURE_LOGD("uri : %s", player->profile.uri);
3049 /* setting property to streaming source */
3050 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3051 "message-forward", TRUE,
3052 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3054 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3055 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "source-setup", G_CALLBACK(__mmplayer_source_setup_cb), (gpointer)player);
3057 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3058 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3060 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3061 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3063 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3064 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3066 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3067 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3069 /* FIXME: need to be added for gapless playback
3070 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3071 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
3074 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3075 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3077 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3078 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3080 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3081 LOGW("[DASH] this is still experimental feature");
3084 return uridecodebin3;
3088 __mmplayer_gst_make_http_src(mmplayer_t *player)
3090 #define MAX_RETRY_COUNT 10
3091 GstElement *element = NULL;
3092 MMHandleType attrs = 0;
3093 gchar *user_agent, *cookies, **cookie_list;
3094 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3096 user_agent = cookies = NULL;
3100 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3102 /* get profile attribute */
3103 attrs = MMPLAYER_GET_ATTRS(player);
3105 LOGE("failed to get content attribute");
3109 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
3111 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3113 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3118 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3119 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3121 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3122 http_timeout = player->ini.http_timeout;
3125 SECURE_LOGD("location : %s", player->profile.uri);
3126 SECURE_LOGD("cookies : %s", cookies);
3127 SECURE_LOGD("user_agent : %s", user_agent);
3128 LOGD("timeout : %d", http_timeout);
3130 /* setting property to streaming source */
3131 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3132 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3133 "retries", MAX_RETRY_COUNT, NULL);
3135 /* parsing cookies */
3136 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3137 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3138 g_strfreev(cookie_list);
3142 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3144 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3145 LOGW("[DASH] this is still experimental feature");
3152 __mmplayer_gst_make_file_src(mmplayer_t *player)
3154 GstElement *element = NULL;
3157 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3159 LOGD("using filesrc for 'file://' handler");
3160 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3161 LOGE("failed to get storage info");
3165 element = gst_element_factory_make("filesrc", "source");
3167 LOGE("failed to create filesrc");
3171 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3178 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3180 mmplayer_t *player = (mmplayer_t *)data;
3182 g_return_val_if_fail(player, FALSE);
3183 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3185 gst_message_ref(msg);
3187 g_mutex_lock(&player->bus_msg_q_lock);
3188 g_queue_push_tail(player->bus_msg_q, msg);
3189 g_mutex_unlock(&player->bus_msg_q_lock);
3191 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3192 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3193 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3197 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3199 mmplayer_t *player = (mmplayer_t *)(data);
3200 GstMessage *msg = NULL;
3204 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3206 player->pipeline->mainbin &&
3207 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3210 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3212 LOGE("cannot get BUS from the pipeline");
3216 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3218 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3219 while (!player->bus_msg_thread_exit) {
3220 g_mutex_lock(&player->bus_msg_q_lock);
3221 msg = g_queue_pop_head(player->bus_msg_q);
3222 g_mutex_unlock(&player->bus_msg_q_lock);
3224 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3227 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3228 /* handle the gst msg */
3229 __mmplayer_gst_bus_msg_callback(msg, player);
3230 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3231 gst_message_unref(msg);
3234 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3235 gst_object_unref(GST_OBJECT(bus));
3242 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3244 gint64 dur_nsec = 0;
3247 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3249 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3250 return MM_ERROR_NONE;
3252 /* NOTE : duration cannot be zero except live streaming.
3253 * Since some element could have some timing problemn with quering duration, try again.
3255 if (player->duration == 0) {
3256 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3257 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3258 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3259 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3260 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3261 player->pending_seek.is_pending = true;
3262 player->pending_seek.pos = position;
3263 player->seek_state = MMPLAYER_SEEK_NONE;
3264 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3265 return MM_ERROR_PLAYER_NO_OP;
3267 player->seek_state = MMPLAYER_SEEK_NONE;
3268 return MM_ERROR_PLAYER_SEEK;
3271 player->duration = dur_nsec;
3274 if (player->duration > 0 && player->duration < position) {
3275 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3276 return MM_ERROR_INVALID_ARGUMENT;
3280 return MM_ERROR_NONE;
3284 __mmplayer_gst_check_seekable(mmplayer_t *player)
3286 GstQuery *query = NULL;
3287 gboolean seekable = FALSE;
3289 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3293 query = gst_query_new_seeking(GST_FORMAT_TIME);
3294 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3295 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3296 gst_query_unref(query);
3299 LOGW("non-seekable content");
3300 player->seek_state = MMPLAYER_SEEK_NONE;
3304 LOGW("failed to get seeking query");
3305 gst_query_unref(query); /* keep seeking operation */
3312 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3314 GstState element_state = GST_STATE_VOID_PENDING;
3315 GstState element_pending_state = GST_STATE_VOID_PENDING;
3316 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3321 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3323 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3326 ret = gst_element_set_state(element, state);
3327 if (ret == GST_STATE_CHANGE_FAILURE) {
3328 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3330 /* dump state of all element */
3331 _mmplayer_dump_pipeline_state(player);
3333 return MM_ERROR_PLAYER_INTERNAL;
3336 /* return here so state transition to be done in async mode */
3338 LOGD("async state transition. not waiting for state complete.");
3339 return MM_ERROR_NONE;
3342 /* wait for state transition */
3343 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3344 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3345 LOGE("failed to change [%s] element state to [%s] within %d sec",
3346 GST_ELEMENT_NAME(element),
3347 gst_element_state_get_name(state), timeout);
3349 LOGE(" [%s] state : %s pending : %s",
3350 GST_ELEMENT_NAME(element),
3351 gst_element_state_get_name(element_state),
3352 gst_element_state_get_name(element_pending_state));
3354 /* dump state of all element */
3355 _mmplayer_dump_pipeline_state(player);
3357 return MM_ERROR_PLAYER_INTERNAL;
3360 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3364 return MM_ERROR_NONE;
3368 _mmplayer_gst_start(mmplayer_t *player)
3370 int ret = MM_ERROR_NONE;
3371 gboolean async = FALSE;
3375 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3377 /* NOTE : if SetPosition was called before Start. do it now
3378 * streaming doesn't support it. so it should be always sync
3379 * !!create one more api to check if there is pending seek rather than checking variables
3381 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3382 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3383 ret = _mmplayer_gst_pause(player, FALSE);
3384 if (ret != MM_ERROR_NONE) {
3385 LOGE("failed to set state to PAUSED for pending seek");
3389 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3390 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3391 LOGW("failed to seek pending postion. starting from the begin of content");
3394 LOGD("current state before doing transition");
3395 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3396 MMPLAYER_PRINT_STATE(player);
3398 /* set pipeline state to PLAYING */
3399 ret = _mmplayer_gst_set_state(player,
3400 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3401 if (ret != MM_ERROR_NONE) {
3402 LOGE("failed to set state to PLAYING");
3406 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3408 /* generating debug info before returning error */
3409 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3417 _mmplayer_gst_stop(mmplayer_t *player)
3419 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3420 MMHandleType attrs = 0;
3421 gboolean rewind = FALSE;
3423 int ret = MM_ERROR_NONE;
3427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3428 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3430 LOGD("current state before doing transition");
3431 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3432 MMPLAYER_PRINT_STATE(player);
3434 attrs = MMPLAYER_GET_ATTRS(player);
3436 LOGE("cannot get content attribute");
3437 return MM_ERROR_PLAYER_INTERNAL;
3440 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3441 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3443 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3444 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3447 if (player->es_player_push_mode)
3448 /* disable the async state transition because there could be no data in the pipeline */
3449 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3452 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3454 if (player->es_player_push_mode) {
3455 /* enable the async state transition as default operation */
3456 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3459 /* return if set_state has failed */
3460 if (ret != MM_ERROR_NONE) {
3461 LOGE("failed to set state.");
3467 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3468 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3469 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3470 LOGW("failed to rewind");
3471 ret = MM_ERROR_PLAYER_SEEK;
3476 player->sent_bos = FALSE;
3478 if (player->es_player_push_mode) //for cloudgame
3481 /* wait for seek to complete */
3482 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3483 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3484 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3486 LOGE("fail to stop player.");
3487 ret = MM_ERROR_PLAYER_INTERNAL;
3488 _mmplayer_dump_pipeline_state(player);
3491 /* generate dot file if enabled */
3492 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3500 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3502 int ret = MM_ERROR_NONE;
3506 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3507 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3509 LOGD("current state before doing transition");
3510 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3511 MMPLAYER_PRINT_STATE(player);
3513 /* set pipeline status to PAUSED */
3514 ret = _mmplayer_gst_set_state(player,
3515 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3520 if (ret != MM_ERROR_NONE) {
3521 GstMessage *msg = NULL;
3522 GTimer *timer = NULL;
3523 gdouble MAX_TIMEOUT_SEC = 3;
3525 LOGE("failed to set state to PAUSED");
3527 if (!player->bus_watcher) {
3528 LOGE("there is no bus msg thread. pipeline is shutting down.");
3532 if (player->msg_posted) {
3533 LOGE("error msg is already posted.");
3537 timer = g_timer_new();
3538 g_timer_start(timer);
3540 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3543 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3545 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3546 GError *error = NULL;
3548 /* parse error code */
3549 gst_message_parse_error(msg, &error, NULL);
3551 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3552 /* Note : the streaming error from the streaming source is handled
3553 * using __mmplayer_handle_streaming_error.
3555 __mmplayer_handle_streaming_error(player, msg);
3558 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3560 if (error->domain == GST_STREAM_ERROR)
3561 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3562 else if (error->domain == GST_RESOURCE_ERROR)
3563 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3564 else if (error->domain == GST_LIBRARY_ERROR)
3565 ret = __mmplayer_gst_handle_library_error(player, error->code);
3566 else if (error->domain == GST_CORE_ERROR)
3567 ret = __mmplayer_gst_handle_core_error(player, error->code);
3569 g_error_free(error);
3571 player->msg_posted = TRUE;
3573 gst_message_unref(msg);
3575 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3577 gst_object_unref(bus);
3578 g_timer_stop(timer);
3579 g_timer_destroy(timer);
3584 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3585 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3586 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3587 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3590 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3593 /* generate dot file before returning error */
3594 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3602 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3604 int ret = MM_ERROR_NONE;
3609 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3610 MM_ERROR_PLAYER_NOT_INITIALIZED);
3612 LOGD("current state before doing transition");
3613 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3614 MMPLAYER_PRINT_STATE(player);
3617 LOGD("do async state transition to PLAYING");
3619 /* set pipeline state to PLAYING */
3620 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3622 ret = _mmplayer_gst_set_state(player,
3623 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3624 if (ret != MM_ERROR_NONE) {
3625 LOGE("failed to set state to PLAYING");
3630 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3633 /* generate dot file */
3634 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3641 /* sending event to one of sinkelements */
3643 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3645 GstEvent *event2 = NULL;
3646 GList *sinks = NULL;
3647 gboolean res = FALSE;
3650 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3651 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3653 /* While adding subtitles in live feeds seek is getting called.
3654 Adding defensive check in framework layer.*/
3655 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3656 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3657 LOGE("Should not send seek event during live playback");
3662 if (player->play_subtitle)
3663 event2 = gst_event_copy((const GstEvent *)event);
3665 sinks = player->sink_elements;
3667 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3669 if (GST_IS_ELEMENT(sink)) {
3670 /* keep ref to the event */
3671 gst_event_ref(event);
3673 if ((res = gst_element_send_event(sink, event))) {
3674 LOGD("sending event[%s] to sink element [%s] success!",
3675 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3677 /* rtsp case, asyn_done is not called after seek during pause state */
3678 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3679 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3680 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3681 LOGD("RTSP seek completed, after pause state..");
3682 player->seek_state = MMPLAYER_SEEK_NONE;
3683 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3689 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3690 sinks = g_list_next(sinks);
3697 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3698 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3701 sinks = g_list_next(sinks);
3704 /* Note : Textbin is not linked to the video or audio bin.
3705 * It needs to send the event to the text sink seperatelly.
3707 if (player->play_subtitle && player->pipeline) {
3708 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3710 if (GST_IS_ELEMENT(text_sink)) {
3711 /* keep ref to the event */
3712 gst_event_ref(event2);
3714 if ((res = gst_element_send_event(text_sink, event2)))
3715 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3716 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3718 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3719 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3721 gst_event_unref(event2);
3725 gst_event_unref(event);
3733 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3734 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3735 gint64 cur, GstSeekType stop_type, gint64 stop)
3737 GstEvent *event = NULL;
3738 gboolean result = FALSE;
3742 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3744 if (player->pipeline && player->pipeline->textbin)
3745 __mmplayer_drop_subtitle(player, FALSE);
3747 event = gst_event_new_seek(rate, format, flags, cur_type,
3748 cur, stop_type, stop);
3750 result = _mmplayer_gst_send_event_to_sink(player, event);
3758 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3760 int ret = MM_ERROR_NONE;
3761 gint64 pos_nsec = 0;
3762 gboolean accurated = FALSE;
3763 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3767 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3769 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3770 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3773 ret = __mmplayer_gst_check_duration(player, position);
3774 if (ret != MM_ERROR_NONE) {
3775 LOGE("failed to check duration 0x%X", ret);
3776 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3779 if (!__mmplayer_gst_check_seekable(player))
3780 return MM_ERROR_PLAYER_NO_OP;
3782 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3783 position, player->playback_rate, player->duration);
3785 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3786 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3787 This causes problem is position calculation during normal pause resume scenarios also.
3788 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3789 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3790 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3791 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3792 LOGW("getting current position failed in seek");
3794 player->last_position = pos_nsec;
3795 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3798 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3799 LOGD("not completed seek");
3800 return MM_ERROR_PLAYER_DOING_SEEK;
3803 if (!internal_called)
3804 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3806 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3807 that's why set position through property. */
3808 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3809 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3810 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3811 (!player->videodec_linked) && (!player->audiodec_linked)) {
3813 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3814 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3816 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3817 player->seek_state = MMPLAYER_SEEK_NONE;
3818 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3820 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3822 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3824 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3826 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3827 GST_FORMAT_TIME, seek_flags,
3828 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3829 LOGE("failed to set position");
3834 /* NOTE : store last seeking point to overcome some bad operation
3835 * (returning zero when getting current position) of some elements
3837 player->last_position = position;
3839 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3840 if (player->playback_rate > 1.0)
3841 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3843 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3844 LOGD("buffering should be reset after seeking");
3845 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3846 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3850 return MM_ERROR_NONE;
3853 player->pending_seek.is_pending = true;
3854 player->pending_seek.pos = position;
3856 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3857 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3858 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3859 player->pending_seek.pos);
3861 return MM_ERROR_NONE;
3864 player->seek_state = MMPLAYER_SEEK_NONE;
3865 return MM_ERROR_PLAYER_SEEK;
3869 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3871 #define TRICKPLAY_OFFSET GST_MSECOND
3873 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3874 gint64 pos_nsec = 0;
3875 gboolean ret = TRUE;
3877 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3878 MM_ERROR_PLAYER_NOT_INITIALIZED);
3880 current_state = MMPLAYER_CURRENT_STATE(player);
3882 /* NOTE : query position except paused state to overcome some bad operation
3883 * please refer to below comments in details
3885 if (current_state != MM_PLAYER_STATE_PAUSED)
3886 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3888 /* NOTE : get last point to overcome some bad operation of some elements
3889 *(returning zero when getting current position in paused state
3890 * and when failed to get postion during seeking
3892 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3893 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3895 if (player->playback_rate < 0.0)
3896 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3898 pos_nsec = player->last_position;
3901 pos_nsec = player->last_position;
3903 player->last_position = pos_nsec;
3905 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3908 if (player->duration > 0 && pos_nsec > player->duration)
3909 pos_nsec = player->duration;
3911 player->last_position = pos_nsec;
3914 *position = pos_nsec;
3916 return MM_ERROR_NONE;
3920 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3922 #define STREAMING_IS_FINISHED 0
3923 #define BUFFERING_MAX_PER 100
3924 #define DEFAULT_PER_VALUE -1
3925 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3927 mmplayer_gst_element_t *mainbin = NULL;
3928 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3929 gint64 buffered_total = 0;
3930 gint64 position = 0;
3931 gint buffered_sec = -1;
3932 GstBufferingMode mode = GST_BUFFERING_STREAM;
3933 gint64 content_size_time = player->duration;
3934 guint64 content_size_bytes = player->http_content_size;
3936 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3938 player->pipeline->mainbin,
3939 MM_ERROR_PLAYER_NOT_INITIALIZED);
3941 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3946 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3947 /* and rtsp is not ready yet. */
3948 LOGW("it's only used for http streaming case");
3949 return MM_ERROR_PLAYER_NO_OP;
3952 if (content_size_time <= 0 || content_size_bytes <= 0) {
3953 LOGW("there is no content size");
3954 return MM_ERROR_NONE;
3957 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3958 LOGW("fail to get current position");
3959 return MM_ERROR_NONE;
3962 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3963 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3965 mainbin = player->pipeline->mainbin;
3966 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3968 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3969 GstQuery *query = NULL;
3970 gint byte_in_rate = 0, byte_out_rate = 0;
3971 gint64 estimated_total = 0;
3973 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3974 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3975 LOGW("fail to get buffering query from queue2");
3977 gst_query_unref(query);
3978 return MM_ERROR_NONE;
3981 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3982 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3984 if (mode == GST_BUFFERING_STREAM) {
3985 /* using only queue in case of push mode(ts / mp3) */
3986 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3987 GST_FORMAT_BYTES, &buffered_total)) {
3988 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3989 end_per = 100 * buffered_total / content_size_bytes;
3992 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3994 guint num_of_ranges = 0;
3995 gint64 start_byte = 0, stop_byte = 0;
3997 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3998 if (estimated_total != STREAMING_IS_FINISHED) {
3999 /* buffered size info from queue2 */
4000 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4001 for (idx = 0; idx < num_of_ranges; idx++) {
4002 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4003 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4005 buffered_total += (stop_byte - start_byte);
4008 end_per = BUFFERING_MAX_PER;
4011 gst_query_unref(query);
4014 if (end_per == DEFAULT_PER_VALUE) {
4015 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4017 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4019 /* buffered size info from multiqueue */
4020 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4021 guint curr_size_bytes = 0;
4022 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4023 "curr-size-bytes", &curr_size_bytes, NULL);
4024 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4025 buffered_total += curr_size_bytes;
4028 if (avg_byterate > 0)
4029 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4030 else if (player->total_maximum_bitrate > 0)
4031 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4032 else if (player->total_bitrate > 0)
4033 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4035 if (buffered_sec >= 0)
4036 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4040 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4041 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4043 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4044 buffered_total, buffered_sec, *start_pos, *end_pos);
4046 return MM_ERROR_NONE;
4050 _mmplayer_gst_create_source(mmplayer_t *player)
4052 GstElement *element = NULL;
4055 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4056 player->pipeline->mainbin, NULL);
4058 /* setup source for gapless play */
4059 switch (player->profile.uri_type) {
4061 case MM_PLAYER_URI_TYPE_FILE:
4062 element = __mmplayer_gst_make_file_src(player);
4064 case MM_PLAYER_URI_TYPE_URL_HTTP:
4065 element = __mmplayer_gst_make_http_src(player);
4068 LOGE("not support uri type %d", player->profile.uri_type);
4073 LOGE("failed to create source element");
4082 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4086 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4088 SECURE_LOGD("uri : %s", player->profile.uri);
4090 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4092 if ((player->v_stream_caps) &&
4093 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4094 return MM_ERROR_PLAYER_INTERNAL;
4096 if ((player->a_stream_caps) &&
4097 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4098 return MM_ERROR_PLAYER_INTERNAL;
4100 if ((player->s_stream_caps) &&
4101 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4102 return MM_ERROR_PLAYER_INTERNAL;
4105 return MM_ERROR_NONE;
4109 __mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4111 mmplayer_gst_element_t *mainbin = NULL;
4112 GstElement *autoplug_elem = NULL;
4115 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4116 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4118 mainbin = player->pipeline->mainbin;
4120 LOGD("uri type %d", player->profile.uri_type);
4122 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4123 if (!autoplug_elem) {
4124 LOGE("failed to create uridecodebin3 element");
4128 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4129 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4130 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4132 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4133 LOGE("failed to add uridecodebin to pipeline");
4137 /* FIXME: required ?*/
4138 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4139 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4140 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4142 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4143 LOGE("failed to create fakesink");
4146 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4148 /* take ownership of fakesink. we are reusing it */
4149 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4151 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4152 LOGE("failed to add fakesink to bin");
4153 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4158 return MM_ERROR_NONE;
4162 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4163 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4165 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4166 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4168 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4169 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4171 return MM_ERROR_PLAYER_INTERNAL;
4175 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4177 mmplayer_gst_element_t *mainbin = NULL;
4178 GstElement *src_elem = NULL;
4179 GstElement *autoplug_elem = NULL;
4180 GList *element_bucket = NULL;
4181 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4184 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4185 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4187 LOGD("uri type %d", player->profile.uri_type);
4189 /* create source element */
4190 switch (player->profile.uri_type) {
4191 case MM_PLAYER_URI_TYPE_URL_RTSP:
4192 src_elem = __mmplayer_gst_make_rtsp_src(player);
4194 case MM_PLAYER_URI_TYPE_URL_HTTP:
4195 if (player->ini.use_uridecodebin3) {
4196 LOGD("uridecodebin include src element.");
4197 return __mmplayer_gst_build_pipeline_with_src(player);
4199 src_elem = __mmplayer_gst_make_http_src(player);
4201 case MM_PLAYER_URI_TYPE_FILE:
4202 if (player->ini.use_uridecodebin3) {
4203 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
4204 LOGE("failed to get storage info");
4207 LOGD("uridecodebin include src element.");
4208 return __mmplayer_gst_build_pipeline_with_src(player);
4210 src_elem = __mmplayer_gst_make_file_src(player);
4212 case MM_PLAYER_URI_TYPE_SS:
4214 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4215 if (player->ini.use_uridecodebin3) {
4216 LOGD("uridecodebin include src element.");
4217 return __mmplayer_gst_build_pipeline_with_src(player);
4220 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4222 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4226 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4227 LOGD("get timeout from ini");
4228 http_timeout = player->ini.http_timeout;
4231 /* setting property to streaming source */
4232 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4235 case MM_PLAYER_URI_TYPE_MEM:
4237 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4239 src_elem = gst_element_factory_make("appsrc", "mem-source");
4241 LOGE("failed to create appsrc element");
4245 g_object_set(src_elem, "stream-type", stream_type,
4246 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4248 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4249 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4250 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4251 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4255 LOGE("not support uri type");
4260 LOGE("failed to create source element");
4261 return MM_ERROR_PLAYER_INTERNAL;
4264 mainbin = player->pipeline->mainbin;
4266 /* take source element */
4267 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4269 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4270 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4271 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4273 /* create next element for auto-plugging */
4274 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4275 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4276 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4277 if (!autoplug_elem) {
4278 LOGE("failed to create typefind element");
4282 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4283 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4284 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4285 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4286 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4287 if (!autoplug_elem) {
4288 LOGE("failed to create decodebin");
4292 /* default size of mq in decodebin is 2M
4293 * but it can cause blocking issue during seeking depends on content. */
4294 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4297 if (autoplug_elem) {
4298 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4299 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4300 mainbin[autoplug_elem_id].gst = autoplug_elem;
4302 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4305 /* add elements to pipeline */
4306 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4307 LOGE("failed to add elements to pipeline");
4311 /* linking elements in the bucket by added order. */
4312 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4313 LOGE("failed to link some elements");
4317 /* FIXME: need to check whether this is required or not. */
4318 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4319 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4320 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4321 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4322 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4324 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4325 LOGE("failed to create fakesink");
4328 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4330 /* take ownership of fakesink. we are reusing it */
4331 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4333 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4334 LOGE("failed to add fakesink to bin");
4335 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4340 g_list_free(element_bucket);
4343 return MM_ERROR_NONE;
4346 g_list_free(element_bucket);
4348 if (mainbin[MMPLAYER_M_SRC].gst)
4349 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4351 if (mainbin[autoplug_elem_id].gst)
4352 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4354 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4355 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4357 mainbin[MMPLAYER_M_SRC].gst = NULL;
4358 mainbin[autoplug_elem_id].gst = NULL;
4359 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4361 return MM_ERROR_PLAYER_INTERNAL;
4365 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4368 mmplayer_gst_element_t *mainbin = NULL;
4371 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4372 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4374 mainbin = player->pipeline->mainbin;
4376 /* connect bus callback */
4377 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4379 LOGE("cannot get bus from pipeline");
4380 return MM_ERROR_PLAYER_INTERNAL;
4383 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4384 player->context.thread_default = g_main_context_get_thread_default();
4385 if (player->context.thread_default == NULL) {
4386 player->context.thread_default = g_main_context_default();
4387 LOGD("thread-default context is the global default context");
4389 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4391 /* set sync handler to get tag synchronously */
4392 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4393 gst_object_unref(GST_OBJECT(bus));
4395 /* create gst bus_msb_cb thread */
4396 g_mutex_init(&player->bus_msg_thread_mutex);
4397 g_cond_init(&player->bus_msg_thread_cond);
4398 player->bus_msg_thread_exit = FALSE;
4399 player->bus_msg_thread =
4400 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4401 if (!player->bus_msg_thread) {
4402 LOGE("failed to create gst BUS msg thread");
4403 g_mutex_clear(&player->bus_msg_thread_mutex);
4404 g_cond_clear(&player->bus_msg_thread_cond);
4405 return MM_ERROR_PLAYER_INTERNAL;
4409 return MM_ERROR_NONE;
4413 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4415 mmplayer_gst_element_t *mainbin = NULL;
4416 MMMessageParamType msg_param = {0,};
4417 GstElement *element = NULL;
4418 MMHandleType attrs = 0;
4420 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4424 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4425 LOGE("player is not initialized");
4429 mainbin = player->pipeline->mainbin;
4430 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4432 attrs = MMPLAYER_GET_ATTRS(player);
4434 LOGE("fail to get attributes");
4438 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4440 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4441 LOGE("failed to parse profile");
4442 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4446 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4447 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4448 LOGE("dash or hls is not supportable");
4449 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4453 element = _mmplayer_gst_create_source(player);
4455 LOGE("no source element was created");
4459 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4460 LOGE("failed to add source element to pipeline");
4461 gst_object_unref(GST_OBJECT(element));
4466 /* take source element */
4467 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4468 mainbin[MMPLAYER_M_SRC].gst = element;
4472 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4473 if (player->streamer == NULL) {
4474 player->streamer = _mm_player_streaming_create();
4475 _mm_player_streaming_initialize(player->streamer, TRUE);
4478 elem_idx = MMPLAYER_M_TYPEFIND;
4479 element = gst_element_factory_make("typefind", "typefinder");
4480 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4481 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4483 elem_idx = MMPLAYER_M_AUTOPLUG;
4484 element = _mmplayer_gst_make_decodebin(player);
4487 /* check autoplug element is OK */
4489 LOGE("can not create element(%d)", elem_idx);
4493 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4494 LOGE("failed to add sinkbin to pipeline");
4495 gst_object_unref(GST_OBJECT(element));
4500 mainbin[elem_idx].id = elem_idx;
4501 mainbin[elem_idx].gst = element;
4503 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4504 LOGE("Failed to link src - autoplug(or typefind)");
4508 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4509 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4510 LOGE("Failed to change state of src element");
4514 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4515 LOGE("Failed to change state of decodebin");
4520 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4521 LOGE("Failed to change state of src element");
4525 player->gapless.stream_changed = TRUE;
4526 player->gapless.running = TRUE;
4532 _mmplayer_set_reconfigure_state(player, FALSE);
4533 if (!player->msg_posted) {
4534 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4535 player->msg_posted = TRUE;