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 <mm_attrs_private.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"
37 /*===========================================================================================
39 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
41 ========================================================================================== */
43 /*---------------------------------------------------------------------------
44 | GLOBAL CONSTANT DEFINITIONS: |
45 ---------------------------------------------------------------------------*/
47 /*---------------------------------------------------------------------------
48 | IMPORTED VARIABLE DECLARATIONS: |
49 ---------------------------------------------------------------------------*/
51 /*---------------------------------------------------------------------------
52 | IMPORTED FUNCTION DECLARATIONS: |
53 ---------------------------------------------------------------------------*/
55 /*---------------------------------------------------------------------------
57 ---------------------------------------------------------------------------*/
59 /*---------------------------------------------------------------------------
60 | LOCAL CONSTANT DEFINITIONS: |
61 ---------------------------------------------------------------------------*/
63 /*---------------------------------------------------------------------------
64 | LOCAL DATA TYPE DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | GLOBAL VARIABLE DEFINITIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | LOCAL VARIABLE DEFINITIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
76 | LOCAL FUNCTION PROTOTYPES: |
77 ---------------------------------------------------------------------------*/
79 /*===========================================================================================
81 | FUNCTION DEFINITIONS |
83 ========================================================================================== */
85 /* NOTE : decide gstreamer state whether there is some playable track or not. */
87 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
89 gchar *src_element_name = NULL;
90 GstElement *src_element = NULL;
91 GstElementFactory *factory = NULL;
92 const gchar* klass = NULL;
96 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
97 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
98 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
99 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
101 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
103 src_element = GST_ELEMENT_CAST(message->src);
107 src_element_name = GST_ELEMENT_NAME(src_element);
108 if (!src_element_name)
111 factory = gst_element_get_factory(src_element);
115 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
119 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
120 error->code, error->message, src_element_name, klass);
122 /* check whether the error is posted from not-activated track or not */
123 if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
125 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
126 LOGD("current active pad index -%d", active_pad_index);
128 if (src_element_name) {
131 if (player->audio_decoders) {
132 GList *adec = player->audio_decoders;
133 for (; adec ; adec = g_list_next(adec)) {
134 gchar *name = adec->data;
136 LOGD("found audio decoder name = %s", name);
137 if (g_strrstr(name, src_element_name)) {
144 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
147 if (active_pad_index != msg_src_pos) {
148 LOGD("skip error because error is posted from no activated track");
149 return MM_ERROR_NONE;
153 switch (error->code) {
154 case GST_STREAM_ERROR_DECODE:
156 /* Demuxer can't parse one track because it's corrupted.
157 * So, the decoder for it is not linked.
158 * But, it has one playable track.
160 if (g_strrstr(klass, "Demux")) {
161 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
162 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
163 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
164 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
166 if (player->pipeline->audiobin) // PCM
167 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
169 goto CODEC_NOT_FOUND;
172 return MM_ERROR_PLAYER_INVALID_STREAM;
176 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
177 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
178 case GST_STREAM_ERROR_WRONG_TYPE:
180 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
181 LOGE("Not supported subtitle.");
182 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
184 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
187 case GST_STREAM_ERROR_FAILED:
189 /* Decoder Custom Message */
190 if (strstr(error->message, "ongoing")) {
191 if (strncasecmp(klass, "audio", 5)) {
192 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
193 LOGD("Video can keep playing.\n");
194 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
196 goto CODEC_NOT_FOUND;
198 } else if (strncasecmp(klass, "video", 5)) {
199 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
200 LOGD("Audio can keep playing.\n");
201 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
203 goto CODEC_NOT_FOUND;
206 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
210 case GST_STREAM_ERROR_DECRYPT:
211 case GST_STREAM_ERROR_DECRYPT_NOKEY:
213 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
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;
223 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
233 return MM_ERROR_PLAYER_INVALID_STREAM;
236 return MM_ERROR_PLAYER_INTERNAL;
239 LOGD("not found any available codec. Player should be destroyed.\n");
240 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
244 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
246 gint trans_err = MM_ERROR_NONE;
250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
253 case GST_CORE_ERROR_MISSING_PLUGIN:
254 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
255 case GST_CORE_ERROR_STATE_CHANGE:
256 case GST_CORE_ERROR_SEEK:
257 case GST_CORE_ERROR_NOT_IMPLEMENTED:
258 case GST_CORE_ERROR_FAILED:
259 case GST_CORE_ERROR_TOO_LAZY:
260 case GST_CORE_ERROR_PAD:
261 case GST_CORE_ERROR_THREAD:
262 case GST_CORE_ERROR_NEGOTIATION:
263 case GST_CORE_ERROR_EVENT:
264 case GST_CORE_ERROR_CAPS:
265 case GST_CORE_ERROR_TAG:
266 case GST_CORE_ERROR_CLOCK:
267 case GST_CORE_ERROR_DISABLED:
269 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
279 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
281 gint trans_err = MM_ERROR_NONE;
285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
288 case GST_LIBRARY_ERROR_FAILED:
289 case GST_LIBRARY_ERROR_TOO_LAZY:
290 case GST_LIBRARY_ERROR_INIT:
291 case GST_LIBRARY_ERROR_SHUTDOWN:
292 case GST_LIBRARY_ERROR_SETTINGS:
293 case GST_LIBRARY_ERROR_ENCODE:
295 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
305 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
307 gint trans_err = MM_ERROR_NONE;
311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
314 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
315 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
317 case GST_RESOURCE_ERROR_NOT_FOUND:
318 case GST_RESOURCE_ERROR_OPEN_READ:
319 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
320 || MMPLAYER_IS_RTSP_STREAMING(player)) {
321 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
324 case GST_RESOURCE_ERROR_READ:
325 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
326 || MMPLAYER_IS_RTSP_STREAMING(player)) {
327 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
329 } else if (message != NULL && message->src != NULL) {
330 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
331 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
333 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
334 path_type = MMPLAYER_PATH_VOD;
335 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
336 path_type = MMPLAYER_PATH_TEXT;
338 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
339 /* check storage state */
340 storage_get_state(player->storage_info[path_type].id, &storage_state);
341 player->storage_info[path_type].state = storage_state;
342 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
345 case GST_RESOURCE_ERROR_WRITE:
346 case GST_RESOURCE_ERROR_FAILED:
347 case GST_RESOURCE_ERROR_SEEK:
348 case GST_RESOURCE_ERROR_TOO_LAZY:
349 case GST_RESOURCE_ERROR_BUSY:
350 case GST_RESOURCE_ERROR_OPEN_WRITE:
351 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
352 case GST_RESOURCE_ERROR_CLOSE:
353 case GST_RESOURCE_ERROR_SYNC:
354 case GST_RESOURCE_ERROR_SETTINGS:
356 trans_err = MM_ERROR_PLAYER_INTERNAL;
366 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
368 gint trans_err = MM_ERROR_NONE;
372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
373 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
374 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
376 switch (error->code) {
377 case GST_STREAM_ERROR_FAILED:
378 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
379 case GST_STREAM_ERROR_DECODE:
380 case GST_STREAM_ERROR_WRONG_TYPE:
381 case GST_STREAM_ERROR_DECRYPT:
382 case GST_STREAM_ERROR_DECRYPT_NOKEY:
383 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
384 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
387 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
388 case GST_STREAM_ERROR_TOO_LAZY:
389 case GST_STREAM_ERROR_ENCODE:
390 case GST_STREAM_ERROR_DEMUX:
391 case GST_STREAM_ERROR_MUX:
392 case GST_STREAM_ERROR_FORMAT:
394 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
404 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
406 MMMessageParamType msg_param;
407 gchar *msg_src_element;
411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
412 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
414 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
416 memset(&msg_param, 0, sizeof(MMMessageParamType));
418 if (error->domain == GST_CORE_ERROR) {
419 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
420 } else if (error->domain == GST_LIBRARY_ERROR) {
421 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
422 } else if (error->domain == GST_RESOURCE_ERROR) {
423 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
424 } else if (error->domain == GST_STREAM_ERROR) {
425 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
427 LOGW("This error domain is not defined.\n");
429 /* we treat system error as an internal error */
430 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
434 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
436 msg_param.data = (void *) error->message;
438 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
439 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
443 if (msg_param.code == MM_ERROR_NONE)
446 /* skip error to avoid duplicated posting */
447 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
448 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
449 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
450 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
452 /* The error will be handled by mused.
453 * @ref _mmplayer_manage_external_storage_state() */
455 LOGW("storage is removed, skip error post");
459 /* post error to application */
460 if (!player->msg_posted) {
461 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
462 /* don't post more if one was sent already */
463 player->msg_posted = TRUE;
465 LOGD("skip error post because it's sent already.\n");
473 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
476 MMMessageParamType msg_param;
477 gchar *msg_src_element = NULL;
478 GstStructure *s = NULL;
480 gchar *error_string = NULL;
484 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
485 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
487 s = gst_structure_copy(gst_message_get_structure(message));
490 if (!gst_structure_get_uint(s, "error_id", &error_id))
491 error_id = MMPLAYER_STREAMING_ERROR_NONE;
494 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
495 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
497 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
498 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
500 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
501 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
503 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
504 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
506 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
507 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
509 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
510 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
512 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
515 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
518 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
521 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
524 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
527 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
530 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
533 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
536 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
539 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
542 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
545 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
548 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
551 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
554 case MMPLAYER_STREAMING_ERROR_GONE:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
557 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
560 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
563 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
566 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
569 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
572 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
575 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
578 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
581 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
584 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
587 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
590 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
593 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
596 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
599 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
602 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
605 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
608 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
611 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
614 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
617 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
620 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
623 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
626 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
631 gst_structure_free(s);
632 return MM_ERROR_PLAYER_STREAMING_FAIL;
636 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
638 msg_param.data = (void *) error_string;
641 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
643 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
644 msg_src_element, msg_param.code, (char*)msg_param.data);
647 /* post error to application */
648 if (!player->msg_posted) {
649 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
651 /* don't post more if one was sent already */
652 player->msg_posted = TRUE;
654 LOGD("skip error post because it's sent already.\n");
656 gst_structure_free(s);
658 g_free(error_string);
665 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
667 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
668 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
669 gst_tag_list_get_string(tags, "stitching_software",
670 &metadata->stitching_software);
671 gst_tag_list_get_string(tags, "projection_type",
672 &metadata->projection_type_string);
673 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
674 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
675 gst_tag_list_get_int(tags, "init_view_heading",
676 &metadata->init_view_heading);
677 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
678 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
679 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
680 gst_tag_list_get_int(tags, "full_pano_width_pixels",
681 &metadata->full_pano_width_pixels);
682 gst_tag_list_get_int(tags, "full_pano_height_pixels",
683 &metadata->full_pano_height_pixels);
684 gst_tag_list_get_int(tags, "cropped_area_image_width",
685 &metadata->cropped_area_image_width);
686 gst_tag_list_get_int(tags, "cropped_area_image_height",
687 &metadata->cropped_area_image_height);
688 gst_tag_list_get_int(tags, "cropped_area_left",
689 &metadata->cropped_area_left);
690 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
691 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
692 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
693 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
697 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
700 /* macro for better code readability */
701 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
702 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
703 if (string != NULL) { \
704 SECURE_LOGD("update tag string : %s\n", string); \
705 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
706 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
707 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
708 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
709 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
710 g_free(new_string); \
713 mm_attrs_set_string_by_name(attribute, playertag, string); \
720 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
722 GstSample *sample = NULL;\
723 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
724 GstMapInfo info = GST_MAP_INFO_INIT;\
725 buffer = gst_sample_get_buffer(sample);\
726 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
727 LOGD("failed to get image data from tag");\
728 gst_sample_unref(sample);\
731 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
732 MMPLAYER_FREEIF(player->album_art);\
733 player->album_art = (gchar *)g_malloc(info.size);\
734 if (player->album_art) {\
735 memcpy(player->album_art, info.data, info.size);\
736 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
737 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
738 msg_param.data = (void *)player->album_art;\
739 msg_param.size = info.size;\
740 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
741 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
744 gst_buffer_unmap(buffer, &info);\
745 gst_sample_unref(sample);\
749 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
751 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
754 gchar *tag_list_str = NULL; \
755 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
756 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
757 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
758 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
759 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
761 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
762 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
763 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
764 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
765 player->bitrate[track_type] = v_uint; \
766 player->total_bitrate = 0; \
767 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
768 player->total_bitrate += player->bitrate[i]; \
769 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
770 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
771 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
772 player->maximum_bitrate[track_type] = v_uint; \
773 player->total_maximum_bitrate = 0; \
774 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
775 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
776 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
777 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
779 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
782 g_free(tag_list_str); \
787 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
788 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
790 string = g_strdup_printf("%d", g_date_get_year(date));\
791 mm_attrs_set_string_by_name(attribute, playertag, string);\
792 SECURE_LOGD("metainfo year : %s\n", string);\
793 MMPLAYER_FREEIF(string);\
798 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
799 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
800 if (datetime != NULL) {\
801 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
802 mm_attrs_set_string_by_name(attribute, playertag, string);\
803 SECURE_LOGD("metainfo year : %s\n", string);\
804 MMPLAYER_FREEIF(string);\
805 gst_date_time_unref(datetime);\
809 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
810 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
812 /* FIXIT : don't know how to store date */\
818 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
821 /* FIXIT : don't know how to store date */\
828 GstTagList* tag_list = NULL;
830 MMHandleType attrs = 0;
835 GstDateTime *datetime = NULL;
837 GstBuffer *buffer = NULL;
839 MMMessageParamType msg_param = {0, };
841 /* currently not used. but those are needed for above macro */
842 //guint64 v_uint64 = 0;
843 //gdouble v_double = 0;
845 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
847 attrs = MMPLAYER_GET_ATTRS(player);
849 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
851 /* get tag list from gst message */
852 gst_message_parse_tag(msg, &tag_list);
854 /* store tags to player attributes */
855 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
856 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
857 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
858 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
859 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
860 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
861 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
862 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
863 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
864 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
865 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
866 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
867 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
868 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
869 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
870 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
871 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
872 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
873 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
874 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
876 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
877 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
878 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
885 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
886 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
887 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
888 MMPLAYER_UPDATE_TAG_LOCK(player);
889 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
890 MMPLAYER_UPDATE_TAG_UNLOCK(player);
891 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
892 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
901 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
902 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
903 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "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_attrs_set_int_by_name(attrs, "content_video_is_spherical",
909 player->video360_metadata.is_spherical);
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.\n", 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.\n", player->video360_metadata.stereo_mode_string);
936 player->is_content_spherical = player->is_video360_enabled = FALSE;
942 if (mmf_attrs_commit(attrs))
943 LOGE("failed to commit.\n");
945 gst_tag_list_free(tag_list);
950 /* if retval is FALSE, it will be dropped for perfomance. */
952 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
954 gboolean retval = FALSE;
956 if (!(player->pipeline && player->pipeline->mainbin)) {
957 LOGE("player pipeline handle is null");
961 switch (GST_MESSAGE_TYPE(message)) {
962 case GST_MESSAGE_TAG:
963 case GST_MESSAGE_EOS:
964 case GST_MESSAGE_ERROR:
965 case GST_MESSAGE_WARNING:
966 case GST_MESSAGE_CLOCK_LOST:
967 case GST_MESSAGE_NEW_CLOCK:
968 case GST_MESSAGE_ELEMENT:
969 case GST_MESSAGE_DURATION_CHANGED:
970 case GST_MESSAGE_ASYNC_START:
973 case GST_MESSAGE_ASYNC_DONE:
974 case GST_MESSAGE_STATE_CHANGED:
975 /* we only handle messages from pipeline */
976 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
981 case GST_MESSAGE_BUFFERING:
983 gint buffer_percent = 0;
986 gst_message_parse_buffering(message, &buffer_percent);
987 if (buffer_percent != MAX_BUFFER_PERCENT) {
988 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
992 if (!MMPLAYER_CMD_TRYLOCK(player)) {
993 LOGW("can't get cmd lock, send msg to bus");
997 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
998 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
999 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1002 MMPLAYER_CMD_UNLOCK(player);
1015 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1017 MMHandleType attrs = 0;
1018 guint64 data_size = 0;
1020 gint64 pos_nsec = 0;
1023 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1025 __mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec); /* to update player->last_position */
1027 attrs = MMPLAYER_GET_ATTRS(player);
1029 LOGE("fail to get attributes.\n");
1033 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1034 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1036 if (stat(path, &sb) == 0)
1037 data_size = (guint64)sb.st_size;
1038 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
1039 data_size = player->http_content_size;
1041 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1042 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1048 __mmplayer_handle_buffering_message(mm_player_t* player)
1050 int ret = MM_ERROR_NONE;
1051 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1052 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1053 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1054 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1056 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1057 LOGW("do nothing for buffering msg\n");
1058 ret = MM_ERROR_PLAYER_INVALID_STATE;
1062 prev_state = MMPLAYER_PREV_STATE(player);
1063 current_state = MMPLAYER_CURRENT_STATE(player);
1064 target_state = MMPLAYER_TARGET_STATE(player);
1065 pending_state = MMPLAYER_PENDING_STATE(player);
1067 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1068 MMPLAYER_STATE_GET_NAME(prev_state),
1069 MMPLAYER_STATE_GET_NAME(current_state),
1070 MMPLAYER_STATE_GET_NAME(pending_state),
1071 MMPLAYER_STATE_GET_NAME(target_state),
1072 player->streamer->buffering_state);
1074 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1075 /* NOTE : if buffering has done, player has to go to target state. */
1076 switch (target_state) {
1077 case MM_PLAYER_STATE_PAUSED:
1079 switch (pending_state) {
1080 case MM_PLAYER_STATE_PLAYING:
1081 __mmplayer_gst_pause(player, TRUE);
1084 case MM_PLAYER_STATE_PAUSED:
1085 LOGD("player is already going to paused state, there is nothing to do.\n");
1088 case MM_PLAYER_STATE_NONE:
1089 case MM_PLAYER_STATE_NULL:
1090 case MM_PLAYER_STATE_READY:
1092 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1098 case MM_PLAYER_STATE_PLAYING:
1100 switch (pending_state) {
1101 case MM_PLAYER_STATE_NONE:
1103 if (current_state != MM_PLAYER_STATE_PLAYING)
1104 __mmplayer_gst_resume(player, TRUE);
1108 case MM_PLAYER_STATE_PAUSED:
1109 /* NOTE: It should be worked as asynchronously.
1110 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1112 if (current_state == MM_PLAYER_STATE_PLAYING) {
1113 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1114 * The current state should be changed to paused purposely to prevent state conflict.
1116 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1118 __mmplayer_gst_resume(player, TRUE);
1121 case MM_PLAYER_STATE_PLAYING:
1122 LOGD("player is already going to playing state, there is nothing to do.\n");
1125 case MM_PLAYER_STATE_NULL:
1126 case MM_PLAYER_STATE_READY:
1128 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1134 case MM_PLAYER_STATE_NULL:
1135 case MM_PLAYER_STATE_READY:
1136 case MM_PLAYER_STATE_NONE:
1138 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1142 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1143 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1145 switch (pending_state) {
1146 case MM_PLAYER_STATE_NONE:
1148 if (current_state != MM_PLAYER_STATE_PAUSED) {
1149 /* rtsp streaming pause makes rtsp server stop sending data. */
1150 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1151 LOGD("set pause state during buffering\n");
1152 __mmplayer_gst_pause(player, TRUE);
1158 case MM_PLAYER_STATE_PLAYING:
1159 /* rtsp streaming pause makes rtsp server stop sending data. */
1160 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1161 __mmplayer_gst_pause(player, TRUE);
1164 case MM_PLAYER_STATE_PAUSED:
1167 case MM_PLAYER_STATE_NULL:
1168 case MM_PLAYER_STATE_READY:
1170 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1179 static VariantData *
1180 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1182 VariantData *var_info = NULL;
1183 g_return_val_if_fail(self != NULL, NULL);
1185 var_info = g_new0(VariantData, 1);
1186 if (!var_info) return NULL;
1187 var_info->bandwidth = self->bandwidth;
1188 var_info->width = self->width;
1189 var_info->height = self->height;
1194 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1200 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1201 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1203 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1204 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1205 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1207 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1208 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1209 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1212 /* handling audio clip which has vbr. means duration is keep changing */
1213 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1222 __mmplayer_eos_timer_cb(gpointer u_data)
1224 mm_player_t* player = NULL;
1225 MMHandleType attrs = 0;
1228 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1230 player = (mm_player_t*) u_data;
1231 attrs = MMPLAYER_GET_ATTRS(player);
1233 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1237 ret_value = __mmplayer_gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
1238 if (ret_value != MM_ERROR_NONE)
1239 LOGE("seeking to 0 failed in repeat play");
1242 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1245 /* we are returning FALSE as we need only one posting */
1250 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1252 MMPLAYER_RETURN_IF_FAIL(player);
1254 /* post now if delay is zero */
1255 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
1256 LOGD("eos delay is zero. posting EOS now\n");
1257 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1259 if (player->set_mode.pcm_extraction)
1260 __mmplayer_cancel_eos_timer(player);
1265 /* cancel if existing */
1266 __mmplayer_cancel_eos_timer(player);
1268 /* init new timeout */
1269 /* NOTE : consider give high priority to this timer */
1270 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1272 player->eos_timer = g_timeout_add(delay_in_ms,
1273 __mmplayer_eos_timer_cb, player);
1275 player->context.global_default = g_main_context_default();
1276 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1278 /* check timer is valid. if not, send EOS now */
1279 if (player->eos_timer == 0) {
1280 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1281 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1285 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1287 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1288 int ret = MM_ERROR_NONE;
1292 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1294 if (!player->pending_seek.is_pending) {
1295 LOGD("pending seek is not reserved. nothing to do.\n");
1299 /* check player state if player could pending seek or not. */
1300 current_state = MMPLAYER_CURRENT_STATE(player);
1302 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1303 LOGW("try to pending seek in %s state, try next time. \n",
1304 MMPLAYER_STATE_GET_NAME(current_state));
1308 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1310 ret = __mmplayer_gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
1312 if (MM_ERROR_NONE != ret)
1313 LOGE("failed to seek pending postion. just keep staying current position.\n");
1315 player->pending_seek.is_pending = FALSE;
1323 __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1325 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1327 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1329 audiobin = player->pipeline->audiobin; /* can be null */
1330 videobin = player->pipeline->videobin; /* can be null */
1331 textbin = player->pipeline->textbin; /* can be null */
1333 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1335 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1336 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1338 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1339 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1341 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1342 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1348 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1350 MMPlayerGstElement *textbin;
1353 MMPLAYER_RETURN_IF_FAIL(player &&
1355 player->pipeline->textbin);
1357 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1359 textbin = player->pipeline->textbin;
1362 LOGD("Drop subtitle text after getting EOS\n");
1364 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
1365 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1367 player->is_subtitle_force_drop = TRUE;
1369 if (player->is_subtitle_force_drop == TRUE) {
1370 LOGD("Enable subtitle data path without drop\n");
1372 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1373 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
1375 LOGD("non-connected with external display");
1377 player->is_subtitle_force_drop = FALSE;
1387 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
1389 GstState element_state = GST_STATE_VOID_PENDING;
1390 GstState element_pending_state = GST_STATE_VOID_PENDING;
1391 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
1395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
1396 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
1398 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
1401 ret = gst_element_set_state(element, state);
1403 if (ret == GST_STATE_CHANGE_FAILURE) {
1404 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
1406 /* dump state of all element */
1407 __mmplayer_dump_pipeline_state(player);
1409 return MM_ERROR_PLAYER_INTERNAL;
1412 /* return here so state transition to be done in async mode */
1414 LOGD("async state transition. not waiting for state complete.\n");
1415 return MM_ERROR_NONE;
1418 /* wait for state transition */
1419 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
1421 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
1422 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
1423 GST_ELEMENT_NAME(element),
1424 gst_element_state_get_name(state), timeout);
1426 LOGE(" [%s] state : %s pending : %s \n",
1427 GST_ELEMENT_NAME(element),
1428 gst_element_state_get_name(element_state),
1429 gst_element_state_get_name(element_pending_state));
1431 /* dump state of all element */
1432 __mmplayer_dump_pipeline_state(player);
1434 return MM_ERROR_PLAYER_INTERNAL;
1437 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
1441 return MM_ERROR_NONE;
1445 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1447 mm_player_t* player = (mm_player_t*)(data);
1449 MMPLAYER_RETURN_IF_FAIL(player);
1450 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1452 switch (GST_MESSAGE_TYPE(msg)) {
1453 case GST_MESSAGE_UNKNOWN:
1454 LOGD("unknown message received\n");
1457 case GST_MESSAGE_EOS:
1459 MMHandleType attrs = 0;
1462 LOGD("GST_MESSAGE_EOS received\n");
1464 /* NOTE : EOS event is comming multiple time. watch out it */
1465 /* check state. we only process EOS when pipeline state goes to PLAYING */
1466 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1467 LOGD("EOS received on non-playing state. ignoring it\n");
1471 if (player->pipeline) {
1472 if (player->pipeline->textbin)
1473 __mmplayer_drop_subtitle(player, TRUE);
1475 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1478 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1480 LOGD("release audio callback\n");
1482 /* release audio callback */
1483 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1484 player->audio_cb_probe_id = 0;
1485 /* audio callback should be free because it can be called even though probe remove.*/
1486 player->audio_stream_cb = NULL;
1487 player->audio_stream_cb_user_param = NULL;
1491 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1492 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1494 /* rewind if repeat count is greater then zero */
1495 /* get play count */
1496 attrs = MMPLAYER_GET_ATTRS(player);
1499 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1501 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1503 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1504 if (player->playback_rate < 0.0) {
1505 player->resumed_by_rewind = TRUE;
1506 _mmplayer_set_mute((MMHandleType)player, 0);
1507 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1510 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1513 player->sent_bos = FALSE;
1515 /* not posting eos when repeating */
1520 if (player->pipeline)
1521 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1523 /* post eos message to application */
1524 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1526 /* reset last position */
1527 player->last_position = 0;
1531 case GST_MESSAGE_ERROR:
1533 GError *error = NULL;
1534 gchar* debug = NULL;
1536 /* generating debug info before returning error */
1537 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1539 /* get error code */
1540 gst_message_parse_error(msg, &error, &debug);
1542 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1543 /* Note : the streaming error from the streaming source is handled
1544 * using __mmplayer_handle_streaming_error.
1546 __mmplayer_handle_streaming_error(player, msg);
1548 /* dump state of all element */
1549 __mmplayer_dump_pipeline_state(player);
1551 /* traslate gst error code to msl error code. then post it
1552 * to application if needed
1554 __mmplayer_handle_gst_error(player, msg, error);
1557 LOGE("error debug : %s", debug);
1560 if (MMPLAYER_IS_HTTP_PD(player))
1561 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1563 MMPLAYER_FREEIF(debug);
1564 g_error_free(error);
1568 case GST_MESSAGE_WARNING:
1571 GError* error = NULL;
1573 gst_message_parse_warning(msg, &error, &debug);
1575 LOGD("warning : %s\n", error->message);
1576 LOGD("debug : %s\n", debug);
1578 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1580 MMPLAYER_FREEIF(debug);
1581 g_error_free(error);
1585 case GST_MESSAGE_TAG:
1587 LOGD("GST_MESSAGE_TAG\n");
1588 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1589 LOGW("failed to extract tags from gstmessage\n");
1593 case GST_MESSAGE_BUFFERING:
1595 MMMessageParamType msg_param = {0, };
1596 int bRet = MM_ERROR_NONE;
1598 if (!(player->pipeline && player->pipeline->mainbin)) {
1599 LOGE("Pipeline is not initialized");
1603 if (!MMPLAYER_IS_STREAMING(player))
1606 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1607 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1608 /* skip the playback control by buffering msg while user request is handled. */
1611 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1613 gst_message_parse_buffering(msg, &per);
1614 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1616 msg_param.connection.buffering = per;
1617 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1621 MMPLAYER_CMD_LOCK(player);
1624 if (!player->streamer) {
1625 LOGW("Pipeline is shutting down");
1626 MMPLAYER_CMD_UNLOCK(player);
1630 /* ignore the remained buffering message till getting 100% msg */
1631 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1632 gint buffer_percent = 0;
1634 gst_message_parse_buffering(msg, &buffer_percent);
1636 if (buffer_percent == MAX_BUFFER_PERCENT) {
1637 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1638 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1640 MMPLAYER_CMD_UNLOCK(player);
1644 /* ignore the remained buffering message */
1645 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1646 gint buffer_percent = 0;
1648 gst_message_parse_buffering(msg, &buffer_percent);
1650 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1651 player->streamer->buffering_percent, buffer_percent);
1653 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1654 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1655 player->streamer->buffering_req.is_pre_buffering = FALSE;
1657 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1659 LOGD("interrupted buffering - ignored the remained buffering msg!");
1660 MMPLAYER_CMD_UNLOCK(player);
1665 __mmplayer_update_buffer_setting(player, msg);
1667 bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1669 if (bRet == MM_ERROR_NONE) {
1670 msg_param.connection.buffering = player->streamer->buffering_percent;
1671 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1673 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1674 player->pending_resume &&
1675 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1677 player->is_external_subtitle_added_now = FALSE;
1678 player->pending_resume = FALSE;
1679 _mmplayer_resume((MMHandleType)player);
1682 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1683 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1685 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1686 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1687 player->seek_state = MMPLAYER_SEEK_NONE;
1688 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1689 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1690 /* Considering the async state trasition in case of RTSP.
1691 After getting state change gst msg, seek cmpleted msg will be posted. */
1692 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1696 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1697 if (!player->streamer) {
1698 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1699 MMPLAYER_CMD_UNLOCK(player);
1703 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1705 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1706 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1708 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1709 msg_param.connection.buffering = player->streamer->buffering_percent;
1710 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1712 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1715 msg_param.connection.buffering = player->streamer->buffering_percent;
1716 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1719 MMPLAYER_CMD_UNLOCK(player);
1723 case GST_MESSAGE_STATE_CHANGED:
1725 MMPlayerGstElement *mainbin;
1726 const GValue *voldstate, *vnewstate, *vpending;
1727 GstState oldstate = GST_STATE_NULL;
1728 GstState newstate = GST_STATE_NULL;
1729 GstState pending = GST_STATE_NULL;
1731 if (!(player->pipeline && player->pipeline->mainbin)) {
1732 LOGE("player pipeline handle is null");
1736 mainbin = player->pipeline->mainbin;
1738 /* we only handle messages from pipeline */
1739 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1742 /* get state info from msg */
1743 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1744 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1745 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1747 if (!voldstate || !vnewstate) {
1748 LOGE("received msg has wrong format.");
1752 oldstate = (GstState)voldstate->data[0].v_int;
1753 newstate = (GstState)vnewstate->data[0].v_int;
1755 pending = (GstState)vpending->data[0].v_int;
1757 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1758 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1759 gst_element_state_get_name((GstState)oldstate),
1760 gst_element_state_get_name((GstState)newstate),
1761 gst_element_state_get_name((GstState)pending));
1763 if (newstate == GST_STATE_PLAYING) {
1764 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1766 int retVal = MM_ERROR_NONE;
1767 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1769 retVal = __mmplayer_gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1771 if (MM_ERROR_NONE != retVal)
1772 LOGE("failed to seek pending postion. just keep staying current position.\n");
1774 player->pending_seek.is_pending = FALSE;
1778 if (oldstate == newstate) {
1779 LOGD("pipeline reports state transition to old state");
1784 case GST_STATE_VOID_PENDING:
1787 case GST_STATE_NULL:
1790 case GST_STATE_READY:
1793 case GST_STATE_PAUSED:
1795 gboolean prepare_async = FALSE;
1797 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1798 __mmplayer_configure_audio_callback(player);
1800 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1801 // managed prepare async case
1802 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1803 LOGD("checking prepare mode for async transition - %d", prepare_async);
1806 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1807 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1809 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1810 __mm_player_streaming_set_content_bitrate(player->streamer,
1811 player->total_maximum_bitrate, player->total_bitrate);
1813 if (player->pending_seek.is_pending) {
1814 LOGW("trying to do pending seek");
1815 MMPLAYER_CMD_LOCK(player);
1816 __mmplayer_gst_pending_seek(player);
1817 MMPLAYER_CMD_UNLOCK(player);
1823 case GST_STATE_PLAYING:
1825 if (MMPLAYER_IS_STREAMING(player)) {
1826 // managed prepare async case when buffering is completed
1827 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1828 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1829 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1830 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1832 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1834 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1835 if (player->streamer->buffering_percent < 100) {
1837 MMMessageParamType msg_param = {0, };
1838 LOGW("Posting Buffering Completed Message to Application !!!");
1840 msg_param.connection.buffering = 100;
1841 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1846 if (player->gapless.stream_changed) {
1847 __mmplayer_update_content_attrs(player, ATTR_ALL);
1848 player->gapless.stream_changed = FALSE;
1851 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1852 player->seek_state = MMPLAYER_SEEK_NONE;
1853 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1864 case GST_MESSAGE_CLOCK_LOST:
1866 GstClock *clock = NULL;
1867 gboolean need_new_clock = FALSE;
1869 gst_message_parse_clock_lost(msg, &clock);
1870 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1872 if (!player->videodec_linked)
1873 need_new_clock = TRUE;
1874 else if (!player->ini.use_system_clock)
1875 need_new_clock = TRUE;
1877 if (need_new_clock) {
1878 LOGD("Provide clock is TRUE, do pause->resume\n");
1879 __mmplayer_gst_pause(player, FALSE);
1880 __mmplayer_gst_resume(player, FALSE);
1885 case GST_MESSAGE_NEW_CLOCK:
1887 GstClock *clock = NULL;
1888 gst_message_parse_new_clock(msg, &clock);
1889 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1893 case GST_MESSAGE_ELEMENT:
1895 const gchar *structure_name;
1896 gint count = 0, idx = 0;
1897 MMHandleType attrs = 0;
1899 attrs = MMPLAYER_GET_ATTRS(player);
1901 LOGE("cannot get content attribute");
1905 if (gst_message_get_structure(msg) == NULL)
1908 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1909 if (!structure_name)
1912 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1914 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1915 const GValue *var_info = NULL;
1917 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1918 if (var_info != NULL) {
1919 if (player->adaptive_info.var_list)
1920 g_list_free_full(player->adaptive_info.var_list, g_free);
1922 /* share addr or copy the list */
1923 player->adaptive_info.var_list =
1924 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1926 count = g_list_length(player->adaptive_info.var_list);
1928 VariantData *temp = NULL;
1930 /* print out for debug */
1931 LOGD("num of variant_info %d", count);
1932 for (idx = 0; idx < count; idx++) {
1933 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1935 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1941 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1942 gint num_buffers = 0;
1943 gint extra_num_buffers = 0;
1945 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1946 player->video_num_buffers = num_buffers;
1947 LOGD("video_num_buffers : %d", player->video_num_buffers);
1950 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1951 player->video_extra_num_buffers = extra_num_buffers;
1952 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1957 if (!strcmp(structure_name, "Language_list")) {
1958 const GValue *lang_list = NULL;
1959 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1960 if (lang_list != NULL) {
1961 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1963 LOGD("Total audio tracks(from parser) = %d \n", count);
1967 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1968 const GValue *lang_list = NULL;
1969 MMPlayerLangStruct *temp = NULL;
1971 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1972 if (lang_list != NULL) {
1973 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1975 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1976 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1977 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1978 if (mmf_attrs_commit(attrs))
1979 LOGE("failed to commit.\n");
1980 LOGD("Total subtitle tracks = %d \n", count);
1983 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1985 LOGD("value of lang_key is %s and lang_code is %s",
1986 temp->language_key, temp->language_code);
1989 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1990 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1995 /* custom message */
1996 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1997 MMMessageParamType msg_param = {0,};
1998 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1999 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
2002 /* custom message for RTSP attribute :
2003 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
2004 sdp which has contents info is received when rtsp connection is opened.
2005 extract duration ,codec info , resolution from sdp and get it by GstMessage */
2006 if (!strcmp(structure_name, "rtspsrc_properties")) {
2008 gchar *audio_codec = NULL;
2009 gchar *video_codec = NULL;
2010 gchar *video_frame_size = NULL;
2012 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
2013 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
2014 player->streaming_type = __mmplayer_get_stream_service_type(player);
2016 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
2017 LOGD("rtsp_audio_codec : %s", audio_codec);
2019 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
2021 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
2022 LOGD("rtsp_video_codec : %s", video_codec);
2024 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
2026 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
2027 LOGD("rtsp_video_frame_size : %s", video_frame_size);
2028 if (video_frame_size) {
2030 char *seperator = strchr(video_frame_size, '-');
2033 char video_width[10] = {0,};
2034 int frame_size_len = strlen(video_frame_size);
2035 int separtor_len = strlen(seperator);
2037 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
2038 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
2041 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
2045 if (mmf_attrs_commit(attrs))
2046 LOGE("failed to commit.\n");
2051 case GST_MESSAGE_DURATION_CHANGED:
2053 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2054 if (!__mmplayer_gst_handle_duration(player, msg))
2055 LOGW("failed to update duration");
2060 case GST_MESSAGE_ASYNC_START:
2061 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2064 case GST_MESSAGE_ASYNC_DONE:
2066 MMPlayerGstElement *mainbin;
2068 if (!(player->pipeline && player->pipeline->mainbin)) {
2069 LOGE("player pipeline handle is null");
2073 mainbin = player->pipeline->mainbin;
2075 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2077 /* we only handle messages from pipeline */
2078 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
2081 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
2082 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
2083 player->seek_state = MMPLAYER_SEEK_NONE;
2084 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2085 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
2086 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
2087 LOGD("sync %s state(%s) with parent state(%s)",
2088 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
2089 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
2090 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
2092 /* In case of streaming, pause is required before finishing seeking by buffering.
2093 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
2094 Because the buffering state is controlled according to the state transition for force resume,
2095 the decodebin state should be paused as player state. */
2096 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
2099 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
2100 (player->streamer) &&
2101 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
2102 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
2103 GstQuery *query = NULL;
2104 gboolean busy = FALSE;
2107 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
2108 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
2109 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
2110 gst_query_parse_buffering_percent(query, &busy, &percent);
2111 gst_query_unref(query);
2113 LOGD("buffered percent(%s): %d\n",
2114 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
2118 __mmplayer_handle_buffering_message(player);
2121 player->seek_state = MMPLAYER_SEEK_COMPLETED;
2127 #if 0 /* delete unnecessary logs */
2128 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2129 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2130 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2131 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2132 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2133 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2134 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2135 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2136 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2137 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2138 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2139 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2140 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2141 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2142 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2149 /* should not call 'gst_message_unref(msg)' */
2154 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2156 mm_player_t *player = (mm_player_t *)data;
2157 GstBusSyncReply reply = GST_BUS_DROP;
2159 if (!(player->pipeline && player->pipeline->mainbin)) {
2160 LOGE("player pipeline handle is null");
2161 return GST_BUS_PASS;
2164 if (!__mmplayer_gst_check_useful_message(player, message)) {
2165 gst_message_unref(message);
2166 return GST_BUS_DROP;
2169 switch (GST_MESSAGE_TYPE(message)) {
2170 case GST_MESSAGE_STATE_CHANGED:
2171 /* post directly for fast launch */
2172 if (player->sync_handler) {
2173 __mmplayer_gst_callback(message, player);
2174 reply = GST_BUS_DROP;
2176 reply = GST_BUS_PASS;
2178 case GST_MESSAGE_TAG:
2179 __mmplayer_gst_extract_tag_from_msg(player, message);
2183 GstTagList *tags = NULL;
2185 gst_message_parse_tag(message, &tags);
2187 LOGE("TAGS received from element \"%s\".\n",
2188 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2190 gst_tag_list_foreach(tags, print_tag, NULL);
2191 gst_tag_list_free(tags);
2199 case GST_MESSAGE_DURATION_CHANGED:
2200 __mmplayer_gst_handle_duration(player, message);
2202 case GST_MESSAGE_ASYNC_DONE:
2203 /* NOTE:Don't call gst_callback directly
2204 * because previous frame can be showed even though this message is received for seek.
2207 reply = GST_BUS_PASS;
2211 if (reply == GST_BUS_DROP)
2212 gst_message_unref(message);
2217 int __mmplayer_gst_start(mm_player_t* player)
2219 int ret = MM_ERROR_NONE;
2220 gboolean async = FALSE;
2224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2226 /* NOTE : if SetPosition was called before Start. do it now */
2227 /* streaming doesn't support it. so it should be always sync */
2228 /* !!create one more api to check if there is pending seek rather than checking variables */
2229 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2230 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2231 ret = __mmplayer_gst_pause(player, FALSE);
2232 if (ret != MM_ERROR_NONE) {
2233 LOGE("failed to set state to PAUSED for pending seek");
2237 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
2238 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
2239 LOGW("failed to seek pending postion. starting from the begin of content");
2242 LOGD("current state before doing transition");
2243 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2244 MMPLAYER_PRINT_STATE(player);
2246 /* set pipeline state to PLAYING */
2247 ret = __mmplayer_gst_set_state(player,
2248 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2250 if (ret == MM_ERROR_NONE) {
2251 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2253 LOGE("failed to set state to PLAYING");
2257 /* generating debug info before returning error */
2258 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
2265 int __mmplayer_gst_stop(mm_player_t* player)
2267 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
2268 MMHandleType attrs = 0;
2269 gboolean rewind = FALSE;
2271 int ret = MM_ERROR_NONE;
2275 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2276 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2278 LOGD("current state before doing transition");
2279 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
2280 MMPLAYER_PRINT_STATE(player);
2282 attrs = MMPLAYER_GET_ATTRS(player);
2284 LOGE("cannot get content attribute\n");
2285 return MM_ERROR_PLAYER_INTERNAL;
2288 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
2289 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2291 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
2292 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
2295 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2296 /* disable the async state transition because there could be no data in the pipeline */
2297 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
2301 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
2303 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2304 /* enable the async state transition as default operation */
2305 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
2308 /* return if set_state has failed */
2309 if (ret != MM_ERROR_NONE) {
2310 LOGE("failed to set state.\n");
2316 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2317 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
2318 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
2319 LOGW("failed to rewind\n");
2320 ret = MM_ERROR_PLAYER_SEEK;
2325 player->sent_bos = FALSE;
2327 if (player->es_player_push_mode) //for cloudgame
2330 /* wait for seek to complete */
2331 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
2332 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
2333 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
2335 LOGE("fail to stop player.\n");
2336 ret = MM_ERROR_PLAYER_INTERNAL;
2337 __mmplayer_dump_pipeline_state(player);
2340 /* generate dot file if enabled */
2341 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
2348 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
2350 int ret = MM_ERROR_NONE;
2354 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2355 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2357 LOGD("current state before doing transition");
2358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
2359 MMPLAYER_PRINT_STATE(player);
2361 /* set pipeline status to PAUSED */
2362 ret = __mmplayer_gst_set_state(player,
2363 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2365 if (FALSE == async) {
2366 if (ret != MM_ERROR_NONE) {
2367 GstMessage *msg = NULL;
2368 GTimer *timer = NULL;
2369 gdouble MAX_TIMEOUT_SEC = 3;
2371 LOGE("failed to set state to PAUSED");
2373 if (!player->bus_watcher) {
2374 LOGE("there is no bus msg thread. pipeline is shutting down.");
2378 if (player->msg_posted) {
2379 LOGE("error msg is already posted.");
2383 timer = g_timer_new();
2384 g_timer_start(timer);
2386 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2389 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
2391 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
2392 GError *error = NULL;
2394 /* parse error code */
2395 gst_message_parse_error(msg, &error, NULL);
2397 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
2398 /* Note : the streaming error from the streaming source is handled
2399 * using __mmplayer_handle_streaming_error.
2401 __mmplayer_handle_streaming_error(player, msg);
2404 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
2406 if (error->domain == GST_STREAM_ERROR)
2407 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
2408 else if (error->domain == GST_RESOURCE_ERROR)
2409 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
2410 else if (error->domain == GST_LIBRARY_ERROR)
2411 ret = __mmplayer_gst_handle_library_error(player, error->code);
2412 else if (error->domain == GST_CORE_ERROR)
2413 ret = __mmplayer_gst_handle_core_error(player, error->code);
2415 g_error_free(error);
2417 player->msg_posted = TRUE;
2419 gst_message_unref(msg);
2421 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
2423 gst_object_unref(bus);
2424 g_timer_stop(timer);
2425 g_timer_destroy(timer);
2429 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
2430 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
2432 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
2435 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
2439 /* generate dot file before returning error */
2440 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
2447 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
2449 int ret = MM_ERROR_NONE;
2454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
2455 MM_ERROR_PLAYER_NOT_INITIALIZED);
2457 LOGD("current state before doing transition");
2458 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2459 MMPLAYER_PRINT_STATE(player);
2462 LOGD("do async state transition to PLAYING");
2464 /* set pipeline state to PLAYING */
2465 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2467 ret = __mmplayer_gst_set_state(player,
2468 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
2469 if (ret != MM_ERROR_NONE) {
2470 LOGE("failed to set state to PLAYING");
2474 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2478 /* generate dot file */
2479 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
2486 /* sending event to one of sinkelements */
2488 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
2490 GstEvent * event2 = NULL;
2491 GList *sinks = NULL;
2492 gboolean res = FALSE;
2495 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2496 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
2498 /* While adding subtitles in live feeds seek is getting called.
2499 Adding defensive check in framework layer.*/
2500 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2501 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
2502 LOGE("Should not send seek event during live playback");
2507 if (player->play_subtitle)
2508 event2 = gst_event_copy((const GstEvent *)event);
2510 sinks = player->sink_elements;
2512 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
2514 if (GST_IS_ELEMENT(sink)) {
2515 /* keep ref to the event */
2516 gst_event_ref(event);
2518 if ((res = gst_element_send_event(sink, event))) {
2519 LOGD("sending event[%s] to sink element [%s] success!\n",
2520 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2522 /* rtsp case, asyn_done is not called after seek during pause state */
2523 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2524 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2525 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
2526 LOGD("RTSP seek completed, after pause state..\n");
2527 player->seek_state = MMPLAYER_SEEK_NONE;
2528 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2534 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2535 sinks = g_list_next(sinks);
2542 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
2543 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2546 sinks = g_list_next(sinks);
2549 /* Note : Textbin is not linked to the video or audio bin.
2550 * It needs to send the event to the text sink seperatelly.
2552 if (player->play_subtitle && player->pipeline) {
2553 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
2555 if (GST_IS_ELEMENT(text_sink)) {
2556 /* keep ref to the event */
2557 gst_event_ref(event2);
2559 if ((res = gst_element_send_event(text_sink, event2)))
2560 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
2561 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2563 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
2564 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2566 gst_event_unref(event2);
2570 gst_event_unref(event);
2578 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
2579 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
2580 gint64 cur, GstSeekType stop_type, gint64 stop)
2582 GstEvent* event = NULL;
2583 gboolean result = FALSE;
2587 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2589 if (player->pipeline && player->pipeline->textbin)
2590 __mmplayer_drop_subtitle(player, FALSE);
2592 event = gst_event_new_seek(rate, format, flags, cur_type,
2593 cur, stop_type, stop);
2595 result = __mmplayer_gst_send_event_to_sink(player, event);
2603 __mmplayer_gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
2605 gint64 dur_nsec = 0;
2606 gint64 pos_nsec = 0;
2607 gboolean ret = TRUE;
2608 gboolean accurated = FALSE;
2609 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
2612 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2613 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
2615 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
2616 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
2619 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2620 /* check duration */
2621 /* NOTE : duration cannot be zero except live streaming.
2622 * Since some element could have some timing problemn with quering duration, try again.
2624 if (player->duration == 0) {
2625 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2626 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2627 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2628 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2629 player->pending_seek.is_pending = TRUE;
2630 player->pending_seek.format = format;
2631 player->pending_seek.pos = position;
2632 player->seek_state = MMPLAYER_SEEK_NONE;
2633 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2634 return MM_ERROR_NONE;
2639 player->duration = dur_nsec;
2642 LOGD("playback rate: %f\n", player->playback_rate);
2644 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
2646 seek_flags |= GST_SEEK_FLAG_ACCURATE;
2648 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
2652 case MM_PLAYER_POS_FORMAT_TIME:
2654 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2655 GstQuery *query = NULL;
2656 gboolean seekable = FALSE;
2658 /* check position is valid or not */
2659 if (position > player->duration)
2662 query = gst_query_new_seeking(GST_FORMAT_TIME);
2663 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2664 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2665 gst_query_unref(query);
2668 LOGW("non-seekable content");
2669 player->seek_state = MMPLAYER_SEEK_NONE;
2670 return MM_ERROR_PLAYER_NO_OP;
2673 LOGW("failed to get seeking query");
2674 gst_query_unref(query); /* keep seeking operation */
2677 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
2679 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
2680 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
2681 This causes problem is position calculation during normal pause resume scenarios also.
2682 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
2683 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2684 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2685 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
2686 LOGW("getting current position failed in seek\n");
2688 player->last_position = pos_nsec;
2689 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
2692 if (player->seek_state != MMPLAYER_SEEK_NONE) {
2693 LOGD("not completed seek");
2694 return MM_ERROR_PLAYER_DOING_SEEK;
2698 if (!internal_called)
2699 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2701 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
2702 gint64 cur_time = 0;
2704 /* get current position */
2705 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
2708 GstEvent *event = gst_event_new_seek(1.0,
2710 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
2711 GST_SEEK_TYPE_SET, cur_time,
2712 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2714 __mmplayer_gst_send_event_to_sink(player, event);
2716 if (!MMPLAYER_IS_RTSP_STREAMING(player))
2717 __mmplayer_gst_pause(player, FALSE);
2720 pos_nsec = position;
2722 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
2723 that's why set position through property. */
2724 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2725 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
2726 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
2727 (!player->videodec_linked) && (!player->audiodec_linked)) {
2729 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
2730 LOGD("[%s] set position =%"GST_TIME_FORMAT,
2731 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
2732 player->seek_state = MMPLAYER_SEEK_NONE;
2733 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2735 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2736 GST_FORMAT_TIME, seek_flags,
2737 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2741 LOGE("failed to set position.");
2747 case MM_PLAYER_POS_FORMAT_PERCENT:
2749 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
2751 if (player->seek_state != MMPLAYER_SEEK_NONE) {
2752 LOGD("not completed seek");
2753 return MM_ERROR_PLAYER_DOING_SEEK;
2756 if (!internal_called)
2757 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2759 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
2760 pos_nsec = (gint64)((position * player->duration) / 100);
2761 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2762 GST_FORMAT_TIME, seek_flags,
2763 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2765 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
2775 /* NOTE : store last seeking point to overcome some bad operation
2776 * (returning zero when getting current position) of some elements
2778 player->last_position = pos_nsec;
2780 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
2781 if (player->playback_rate > 1.0)
2782 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
2784 if ((!internal_called) &&
2785 (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
2786 LOGD("buffering should be reset after seeking");
2787 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
2788 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
2792 return MM_ERROR_NONE;
2795 player->pending_seek.is_pending = TRUE;
2796 player->pending_seek.format = format;
2797 player->pending_seek.pos = position;
2799 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
2800 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
2801 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
2802 player->pending_seek.pos);
2804 return MM_ERROR_NONE;
2807 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
2808 return MM_ERROR_INVALID_ARGUMENT;
2811 player->seek_state = MMPLAYER_SEEK_NONE;
2812 return MM_ERROR_PLAYER_SEEK;
2816 __mmplayer_gst_get_position(mm_player_t* player, int format, gint64* position)
2818 #define TRICKPLAY_OFFSET GST_MSECOND
2820 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
2821 gint64 pos_nsec = 0;
2822 gboolean ret = TRUE;
2824 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
2825 MM_ERROR_PLAYER_NOT_INITIALIZED);
2827 current_state = MMPLAYER_CURRENT_STATE(player);
2829 /* NOTE : query position except paused state to overcome some bad operation
2830 * please refer to below comments in details
2832 if (current_state != MM_PLAYER_STATE_PAUSED)
2833 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
2835 /* NOTE : get last point to overcome some bad operation of some elements
2836 *(returning zero when getting current position in paused state
2837 * and when failed to get postion during seeking
2839 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
2840 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
2842 if (player->playback_rate < 0.0)
2843 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
2845 pos_nsec = player->last_position;
2848 pos_nsec = player->last_position;
2850 player->last_position = pos_nsec;
2852 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
2855 if (player->duration > 0 && pos_nsec > player->duration)
2856 pos_nsec = player->duration;
2858 player->last_position = pos_nsec;
2862 case MM_PLAYER_POS_FORMAT_TIME:
2863 *position = pos_nsec;
2866 case MM_PLAYER_POS_FORMAT_PERCENT:
2868 if (player->duration <= 0) {
2869 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
2872 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
2873 *position = (gint64)(pos_nsec * 100 / player->duration);
2878 return MM_ERROR_PLAYER_INTERNAL;
2881 return MM_ERROR_NONE;
2884 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
2886 #define STREAMING_IS_FINISHED 0
2887 #define BUFFERING_MAX_PER 100
2888 #define DEFAULT_PER_VALUE -1
2889 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
2891 MMPlayerGstElement *mainbin = NULL;
2892 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
2893 gint64 buffered_total = 0;
2894 gint64 position = 0;
2895 gint buffered_sec = -1;
2896 GstBufferingMode mode = GST_BUFFERING_STREAM;
2897 gint64 content_size_time = player->duration;
2898 guint64 content_size_bytes = player->http_content_size;
2900 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2902 player->pipeline->mainbin,
2903 MM_ERROR_PLAYER_NOT_INITIALIZED);
2905 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
2910 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
2911 /* and rtsp is not ready yet. */
2912 LOGW("it's only used for http streaming case.\n");
2913 return MM_ERROR_PLAYER_NO_OP;
2916 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
2917 LOGW("Time format is not supported yet.\n");
2918 return MM_ERROR_INVALID_ARGUMENT;
2921 if (content_size_time <= 0 || content_size_bytes <= 0) {
2922 LOGW("there is no content size.");
2923 return MM_ERROR_NONE;
2926 if (__mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
2927 LOGW("fail to get current position.");
2928 return MM_ERROR_NONE;
2931 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
2932 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
2934 mainbin = player->pipeline->mainbin;
2935 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
2937 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
2938 GstQuery *query = NULL;
2939 gint byte_in_rate = 0, byte_out_rate = 0;
2940 gint64 estimated_total = 0;
2942 query = gst_query_new_buffering(GST_FORMAT_BYTES);
2943 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
2944 LOGW("fail to get buffering query from queue2");
2946 gst_query_unref(query);
2947 return MM_ERROR_NONE;
2950 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
2951 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
2953 if (mode == GST_BUFFERING_STREAM) {
2954 /* using only queue in case of push mode(ts / mp3) */
2955 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
2956 GST_FORMAT_BYTES, &buffered_total)) {
2957 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
2958 stop_per = 100 * buffered_total / content_size_bytes;
2961 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
2963 guint num_of_ranges = 0;
2964 gint64 start_byte = 0, stop_byte = 0;
2966 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
2967 if (estimated_total != STREAMING_IS_FINISHED) {
2968 /* buffered size info from queue2 */
2969 num_of_ranges = gst_query_get_n_buffering_ranges(query);
2970 for (idx = 0; idx < num_of_ranges; idx++) {
2971 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
2972 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
2974 buffered_total += (stop_byte - start_byte);
2977 stop_per = BUFFERING_MAX_PER;
2979 gst_query_unref(query);
2982 if (stop_per == DEFAULT_PER_VALUE) {
2983 guint dur_sec = (guint)(content_size_time/GST_SECOND);
2985 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
2987 /* buffered size info from multiqueue */
2988 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
2989 guint curr_size_bytes = 0;
2990 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
2991 "curr-size-bytes", &curr_size_bytes, NULL);
2992 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
2993 buffered_total += curr_size_bytes;
2996 if (avg_byterate > 0)
2997 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
2998 else if (player->total_maximum_bitrate > 0)
2999 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3000 else if (player->total_bitrate > 0)
3001 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3003 if (buffered_sec >= 0)
3004 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3008 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3009 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3011 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
3012 buffered_total, buffered_sec, *start_pos, *stop_pos);
3014 return MM_ERROR_NONE;