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);
657 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_playback(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;
1383 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1385 MMHandleType attrs = 0;
1390 /* NOTE : EOS event is comming multiple time. watch out it */
1391 /* check state. we only process EOS when pipeline state goes to PLAYING */
1392 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1393 LOGD("EOS received on non-playing state. ignoring it");
1397 if (player->pipeline) {
1398 if (player->pipeline->textbin)
1399 __mmplayer_drop_subtitle(player, TRUE);
1401 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1404 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1406 LOGD("release audio callback");
1408 /* release audio callback */
1409 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1410 player->audio_cb_probe_id = 0;
1411 /* audio callback should be free because it can be called even though probe remove.*/
1412 player->audio_stream_cb = NULL;
1413 player->audio_stream_cb_user_param = NULL;
1417 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1418 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1420 /* rewind if repeat count is greater then zero */
1421 /* get play count */
1422 attrs = MMPLAYER_GET_ATTRS(player);
1425 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1427 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1429 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1430 if (player->playback_rate < 0.0) {
1431 player->resumed_by_rewind = TRUE;
1432 _mmplayer_set_mute((MMHandleType)player, 0);
1433 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1436 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1439 player->sent_bos = FALSE;
1441 LOGD("do not post eos msg for repeating");
1446 if (player->pipeline)
1447 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1449 /* post eos message to application */
1450 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1452 /* reset last position */
1453 player->last_position = 0;
1460 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1462 GError *error = NULL;
1463 gchar* debug = NULL;
1467 /* generating debug info before returning error */
1468 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1470 /* get error code */
1471 gst_message_parse_error(msg, &error, &debug);
1473 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1474 /* Note : the streaming error from the streaming source is handled
1475 * using __mmplayer_handle_streaming_error.
1477 __mmplayer_handle_streaming_error(player, msg);
1479 /* dump state of all element */
1480 __mmplayer_dump_pipeline_state(player);
1482 /* traslate gst error code to msl error code. then post it
1483 * to application if needed
1485 __mmplayer_handle_gst_error(player, msg, error);
1488 LOGE("error debug : %s", debug);
1491 if (MMPLAYER_IS_HTTP_PD(player))
1492 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1494 MMPLAYER_FREEIF(debug);
1495 g_error_free(error);
1502 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1504 MMMessageParamType msg_param = {0, };
1505 int bRet = MM_ERROR_NONE;
1508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1510 if (!MMPLAYER_IS_STREAMING(player)) {
1511 LOGW("this is not streaming playback.");
1515 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1516 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1517 /* skip the playback control by buffering msg while user request is handled. */
1520 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1522 gst_message_parse_buffering(msg, &per);
1523 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1525 msg_param.connection.buffering = per;
1526 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1530 MMPLAYER_CMD_LOCK(player);
1533 if (!player->streamer) {
1534 LOGW("Pipeline is shutting down");
1535 MMPLAYER_CMD_UNLOCK(player);
1539 /* ignore the remained buffering message till getting 100% msg */
1540 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1541 gint buffer_percent = 0;
1543 gst_message_parse_buffering(msg, &buffer_percent);
1545 if (buffer_percent == MAX_BUFFER_PERCENT) {
1546 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1547 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1549 MMPLAYER_CMD_UNLOCK(player);
1553 /* ignore the remained buffering message */
1554 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1555 gint buffer_percent = 0;
1557 gst_message_parse_buffering(msg, &buffer_percent);
1559 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1560 player->streamer->buffering_percent, buffer_percent);
1562 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1563 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1564 player->streamer->buffering_req.is_pre_buffering = FALSE;
1566 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1568 LOGD("interrupted buffering - ignored the remained buffering msg!");
1569 MMPLAYER_CMD_UNLOCK(player);
1574 __mmplayer_update_buffer_setting(player, msg);
1576 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1578 if (bRet == MM_ERROR_NONE) {
1579 msg_param.connection.buffering = player->streamer->buffering_percent;
1580 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1582 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1583 player->pending_resume &&
1584 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1586 player->is_external_subtitle_added_now = FALSE;
1587 player->pending_resume = FALSE;
1588 _mmplayer_resume((MMHandleType)player);
1591 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1592 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1594 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1595 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1596 player->seek_state = MMPLAYER_SEEK_NONE;
1597 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1598 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1599 /* Considering the async state trasition in case of RTSP.
1600 After getting state change gst msg, seek cmpleted msg will be posted. */
1601 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1605 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1606 if (!player->streamer) {
1607 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1608 MMPLAYER_CMD_UNLOCK(player);
1612 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1614 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1615 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1617 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1618 msg_param.connection.buffering = player->streamer->buffering_percent;
1619 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1621 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1624 msg_param.connection.buffering = player->streamer->buffering_percent;
1625 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1628 MMPLAYER_CMD_UNLOCK(player);
1636 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1638 MMPlayerGstElement *mainbin;
1639 const GValue *voldstate, *vnewstate, *vpending;
1640 GstState oldstate = GST_STATE_NULL;
1641 GstState newstate = GST_STATE_NULL;
1642 GstState pending = GST_STATE_NULL;
1645 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1647 mainbin = player->pipeline->mainbin;
1649 /* we only handle messages from pipeline */
1650 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1653 /* get state info from msg */
1654 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1655 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1656 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1658 if (!voldstate || !vnewstate) {
1659 LOGE("received msg has wrong format.");
1663 oldstate = (GstState)voldstate->data[0].v_int;
1664 newstate = (GstState)vnewstate->data[0].v_int;
1666 pending = (GstState)vpending->data[0].v_int;
1668 LOGD("state changed [%s] : %s ---> %s final : %s",
1669 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1670 gst_element_state_get_name((GstState)oldstate),
1671 gst_element_state_get_name((GstState)newstate),
1672 gst_element_state_get_name((GstState)pending));
1674 if (newstate == GST_STATE_PLAYING) {
1675 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1677 int retVal = MM_ERROR_NONE;
1678 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1680 retVal = __mmplayer_gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1682 if (MM_ERROR_NONE != retVal)
1683 LOGE("failed to seek pending postion. just keep staying current position.");
1685 player->pending_seek.is_pending = FALSE;
1689 if (oldstate == newstate) {
1690 LOGD("pipeline reports state transition to old state");
1695 case GST_STATE_PAUSED:
1697 gboolean prepare_async = FALSE;
1699 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1700 __mmplayer_configure_audio_callback(player);
1702 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1703 // managed prepare async case
1704 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1705 LOGD("checking prepare mode for async transition - %d", prepare_async);
1708 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1709 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1711 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1712 __mm_player_streaming_set_content_bitrate(player->streamer,
1713 player->total_maximum_bitrate, player->total_bitrate);
1715 if (player->pending_seek.is_pending) {
1716 LOGW("trying to do pending seek");
1717 MMPLAYER_CMD_LOCK(player);
1718 __mmplayer_gst_pending_seek(player);
1719 MMPLAYER_CMD_UNLOCK(player);
1725 case GST_STATE_PLAYING:
1727 if (MMPLAYER_IS_STREAMING(player)) {
1728 // managed prepare async case when buffering is completed
1729 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1730 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1731 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1732 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1734 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1736 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1737 if (player->streamer->buffering_percent < 100) {
1739 MMMessageParamType msg_param = {0, };
1740 LOGW("Posting Buffering Completed Message to Application !!!");
1742 msg_param.connection.buffering = 100;
1743 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1748 if (player->gapless.stream_changed) {
1749 __mmplayer_update_content_attrs(player, ATTR_ALL);
1750 player->gapless.stream_changed = FALSE;
1753 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1754 player->seek_state = MMPLAYER_SEEK_NONE;
1755 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1759 case GST_STATE_VOID_PENDING:
1760 case GST_STATE_NULL:
1761 case GST_STATE_READY:
1771 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1773 const gchar *structure_name;
1774 gint count = 0, idx = 0;
1775 MMHandleType attrs = 0;
1778 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1780 attrs = MMPLAYER_GET_ATTRS(player);
1782 LOGE("Failed to get content attribute");
1786 if (gst_message_get_structure(msg) == NULL)
1789 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1790 if (!structure_name)
1793 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1795 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1796 const GValue *var_info = NULL;
1798 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1799 if (var_info != NULL) {
1800 if (player->adaptive_info.var_list)
1801 g_list_free_full(player->adaptive_info.var_list, g_free);
1803 /* share addr or copy the list */
1804 player->adaptive_info.var_list =
1805 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1807 count = g_list_length(player->adaptive_info.var_list);
1809 VariantData *temp = NULL;
1811 /* print out for debug */
1812 LOGD("num of variant_info %d", count);
1813 for (idx = 0; idx < count; idx++) {
1814 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1816 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1822 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1823 gint num_buffers = 0;
1824 gint extra_num_buffers = 0;
1826 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1827 player->video_num_buffers = num_buffers;
1828 LOGD("video_num_buffers : %d", player->video_num_buffers);
1831 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1832 player->video_extra_num_buffers = extra_num_buffers;
1833 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1838 if (!strcmp(structure_name, "Language_list")) {
1839 const GValue *lang_list = NULL;
1840 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1841 if (lang_list != NULL) {
1842 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1844 LOGD("Total audio tracks(from parser) = %d \n", count);
1848 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1849 const GValue *lang_list = NULL;
1850 MMPlayerLangStruct *temp = NULL;
1852 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1853 if (lang_list != NULL) {
1854 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1856 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1857 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1858 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1859 if (mmf_attrs_commit(attrs))
1860 LOGE("failed to commit.\n");
1861 LOGD("Total subtitle tracks = %d \n", count);
1864 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1866 LOGD("value of lang_key is %s and lang_code is %s",
1867 temp->language_key, temp->language_code);
1870 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1871 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1876 /* custom message */
1877 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1878 MMMessageParamType msg_param = {0,};
1879 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1880 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1883 /* custom message for RTSP attribute :
1884 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1885 sdp which has contents info is received when rtsp connection is opened.
1886 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1887 if (!strcmp(structure_name, "rtspsrc_properties")) {
1889 gchar *audio_codec = NULL;
1890 gchar *video_codec = NULL;
1891 gchar *video_frame_size = NULL;
1893 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1894 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1895 player->streaming_type = __mmplayer_get_stream_service_type(player);
1897 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1898 LOGD("rtsp_audio_codec : %s", audio_codec);
1900 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1902 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1903 LOGD("rtsp_video_codec : %s", video_codec);
1905 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1907 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1908 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1909 if (video_frame_size) {
1911 char *seperator = strchr(video_frame_size, '-');
1914 char video_width[10] = {0,};
1915 int frame_size_len = strlen(video_frame_size);
1916 int separtor_len = strlen(seperator);
1918 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1919 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1922 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1926 if (mmf_attrs_commit(attrs))
1927 LOGE("failed to commit.\n");
1935 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1937 MMPlayerGstElement *mainbin;
1940 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1942 mainbin = player->pipeline->mainbin;
1944 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1946 /* we only handle messages from pipeline */
1947 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1950 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1951 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1952 player->seek_state = MMPLAYER_SEEK_NONE;
1953 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1954 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1955 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1956 LOGD("sync %s state(%s) with parent state(%s)",
1957 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1958 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1959 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1961 /* In case of streaming, pause is required before finishing seeking by buffering.
1962 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1963 Because the buffering state is controlled according to the state transition for force resume,
1964 the decodebin state should be paused as player state. */
1965 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1968 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1969 (player->streamer) &&
1970 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1971 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1972 GstQuery *query = NULL;
1973 gboolean busy = FALSE;
1976 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1977 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1978 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1979 gst_query_parse_buffering_percent(query, &busy, &percent);
1980 gst_query_unref(query);
1982 LOGD("buffered percent(%s): %d\n",
1983 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1987 __mmplayer_handle_buffering_playback(player);
1990 player->seek_state = MMPLAYER_SEEK_COMPLETED;
2003 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2005 GstState element_state = GST_STATE_VOID_PENDING;
2006 GstState element_pending_state = GST_STATE_VOID_PENDING;
2007 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2012 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2014 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2017 ret = gst_element_set_state(element, state);
2019 if (ret == GST_STATE_CHANGE_FAILURE) {
2020 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2022 /* dump state of all element */
2023 __mmplayer_dump_pipeline_state(player);
2025 return MM_ERROR_PLAYER_INTERNAL;
2028 /* return here so state transition to be done in async mode */
2030 LOGD("async state transition. not waiting for state complete.\n");
2031 return MM_ERROR_NONE;
2034 /* wait for state transition */
2035 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2037 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2038 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
2039 GST_ELEMENT_NAME(element),
2040 gst_element_state_get_name(state), timeout);
2042 LOGE(" [%s] state : %s pending : %s \n",
2043 GST_ELEMENT_NAME(element),
2044 gst_element_state_get_name(element_state),
2045 gst_element_state_get_name(element_pending_state));
2047 /* dump state of all element */
2048 __mmplayer_dump_pipeline_state(player);
2050 return MM_ERROR_PLAYER_INTERNAL;
2053 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
2057 return MM_ERROR_NONE;
2061 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
2063 mm_player_t* player = (mm_player_t*)(data);
2065 MMPLAYER_RETURN_IF_FAIL(player);
2066 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2068 switch (GST_MESSAGE_TYPE(msg)) {
2069 case GST_MESSAGE_UNKNOWN:
2070 LOGD("unknown message received\n");
2073 case GST_MESSAGE_EOS:
2074 LOGD("GST_MESSAGE_EOS received");
2075 __mmplayer_gst_handle_eos_message(player, msg);
2078 case GST_MESSAGE_ERROR:
2079 __mmplayer_gst_handle_error_message(player, msg);
2082 case GST_MESSAGE_WARNING:
2085 GError* error = NULL;
2087 gst_message_parse_warning(msg, &error, &debug);
2089 LOGD("warning : %s\n", error->message);
2090 LOGD("debug : %s\n", debug);
2092 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2094 MMPLAYER_FREEIF(debug);
2095 g_error_free(error);
2099 case GST_MESSAGE_TAG:
2101 LOGD("GST_MESSAGE_TAG\n");
2102 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2103 LOGW("failed to extract tags from gstmessage\n");
2107 case GST_MESSAGE_BUFFERING:
2108 __mmplayer_gst_handle_buffering_message(player, msg);
2111 case GST_MESSAGE_STATE_CHANGED:
2112 __mmplayer_gst_handle_state_message(player, msg);
2115 case GST_MESSAGE_CLOCK_LOST:
2117 GstClock *clock = NULL;
2118 gboolean need_new_clock = FALSE;
2120 gst_message_parse_clock_lost(msg, &clock);
2121 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2123 if (!player->videodec_linked)
2124 need_new_clock = TRUE;
2125 else if (!player->ini.use_system_clock)
2126 need_new_clock = TRUE;
2128 if (need_new_clock) {
2129 LOGD("Provide clock is TRUE, do pause->resume\n");
2130 __mmplayer_gst_pause(player, FALSE);
2131 __mmplayer_gst_resume(player, FALSE);
2136 case GST_MESSAGE_NEW_CLOCK:
2138 GstClock *clock = NULL;
2139 gst_message_parse_new_clock(msg, &clock);
2140 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2144 case GST_MESSAGE_ELEMENT:
2145 __mmplayer_gst_handle_element_message(player, msg);
2148 case GST_MESSAGE_DURATION_CHANGED:
2150 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2151 if (!__mmplayer_gst_handle_duration(player, msg))
2152 LOGW("failed to update duration");
2156 case GST_MESSAGE_ASYNC_START:
2157 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2160 case GST_MESSAGE_ASYNC_DONE:
2161 __mmplayer_gst_handle_async_done_message(player, msg);
2164 #if 0 /* delete unnecessary logs */
2165 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2166 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2167 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2168 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2169 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2170 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2171 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2172 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2173 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2174 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2175 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2176 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2177 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2178 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2179 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2186 /* should not call 'gst_message_unref(msg)' */
2191 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2193 mm_player_t *player = (mm_player_t *)data;
2194 GstBusSyncReply reply = GST_BUS_DROP;
2196 if (!(player->pipeline && player->pipeline->mainbin)) {
2197 LOGE("player pipeline handle is null");
2198 return GST_BUS_PASS;
2201 if (!__mmplayer_gst_check_useful_message(player, message)) {
2202 gst_message_unref(message);
2203 return GST_BUS_DROP;
2206 switch (GST_MESSAGE_TYPE(message)) {
2207 case GST_MESSAGE_STATE_CHANGED:
2208 /* post directly for fast launch */
2209 if (player->sync_handler) {
2210 __mmplayer_gst_bus_msg_callback(message, player);
2211 reply = GST_BUS_DROP;
2213 reply = GST_BUS_PASS;
2215 case GST_MESSAGE_TAG:
2216 __mmplayer_gst_extract_tag_from_msg(player, message);
2220 GstTagList *tags = NULL;
2222 gst_message_parse_tag(message, &tags);
2224 LOGE("TAGS received from element \"%s\".\n",
2225 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2227 gst_tag_list_foreach(tags, print_tag, NULL);
2228 gst_tag_list_free(tags);
2236 case GST_MESSAGE_DURATION_CHANGED:
2237 __mmplayer_gst_handle_duration(player, message);
2239 case GST_MESSAGE_ASYNC_DONE:
2240 /* NOTE:Don't call gst_callback directly
2241 * because previous frame can be showed even though this message is received for seek.
2244 reply = GST_BUS_PASS;
2248 if (reply == GST_BUS_DROP)
2249 gst_message_unref(message);
2254 int __mmplayer_gst_start(mm_player_t* player)
2256 int ret = MM_ERROR_NONE;
2257 gboolean async = FALSE;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2263 /* NOTE : if SetPosition was called before Start. do it now */
2264 /* streaming doesn't support it. so it should be always sync */
2265 /* !!create one more api to check if there is pending seek rather than checking variables */
2266 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2267 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2268 ret = __mmplayer_gst_pause(player, FALSE);
2269 if (ret != MM_ERROR_NONE) {
2270 LOGE("failed to set state to PAUSED for pending seek");
2274 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
2275 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
2276 LOGW("failed to seek pending postion. starting from the begin of content");
2279 LOGD("current state before doing transition");
2280 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2281 MMPLAYER_PRINT_STATE(player);
2283 /* set pipeline state to PLAYING */
2284 ret = __mmplayer_gst_set_state(player,
2285 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2287 if (ret == MM_ERROR_NONE) {
2288 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2290 LOGE("failed to set state to PLAYING");
2294 /* generating debug info before returning error */
2295 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
2302 int __mmplayer_gst_stop(mm_player_t* player)
2304 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
2305 MMHandleType attrs = 0;
2306 gboolean rewind = FALSE;
2308 int ret = MM_ERROR_NONE;
2312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2313 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2315 LOGD("current state before doing transition");
2316 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
2317 MMPLAYER_PRINT_STATE(player);
2319 attrs = MMPLAYER_GET_ATTRS(player);
2321 LOGE("cannot get content attribute\n");
2322 return MM_ERROR_PLAYER_INTERNAL;
2325 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
2326 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2328 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
2329 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
2332 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2333 /* disable the async state transition because there could be no data in the pipeline */
2334 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
2338 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
2340 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2341 /* enable the async state transition as default operation */
2342 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
2345 /* return if set_state has failed */
2346 if (ret != MM_ERROR_NONE) {
2347 LOGE("failed to set state.\n");
2353 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2354 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
2355 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
2356 LOGW("failed to rewind\n");
2357 ret = MM_ERROR_PLAYER_SEEK;
2362 player->sent_bos = FALSE;
2364 if (player->es_player_push_mode) //for cloudgame
2367 /* wait for seek to complete */
2368 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
2369 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
2370 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
2372 LOGE("fail to stop player.\n");
2373 ret = MM_ERROR_PLAYER_INTERNAL;
2374 __mmplayer_dump_pipeline_state(player);
2377 /* generate dot file if enabled */
2378 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
2385 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
2387 int ret = MM_ERROR_NONE;
2391 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2392 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2394 LOGD("current state before doing transition");
2395 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
2396 MMPLAYER_PRINT_STATE(player);
2398 /* set pipeline status to PAUSED */
2399 ret = __mmplayer_gst_set_state(player,
2400 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2402 if (FALSE == async) {
2403 if (ret != MM_ERROR_NONE) {
2404 GstMessage *msg = NULL;
2405 GTimer *timer = NULL;
2406 gdouble MAX_TIMEOUT_SEC = 3;
2408 LOGE("failed to set state to PAUSED");
2410 if (!player->bus_watcher) {
2411 LOGE("there is no bus msg thread. pipeline is shutting down.");
2415 if (player->msg_posted) {
2416 LOGE("error msg is already posted.");
2420 timer = g_timer_new();
2421 g_timer_start(timer);
2423 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2426 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
2428 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
2429 GError *error = NULL;
2431 /* parse error code */
2432 gst_message_parse_error(msg, &error, NULL);
2434 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
2435 /* Note : the streaming error from the streaming source is handled
2436 * using __mmplayer_handle_streaming_error.
2438 __mmplayer_handle_streaming_error(player, msg);
2441 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
2443 if (error->domain == GST_STREAM_ERROR)
2444 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
2445 else if (error->domain == GST_RESOURCE_ERROR)
2446 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
2447 else if (error->domain == GST_LIBRARY_ERROR)
2448 ret = __mmplayer_gst_handle_library_error(player, error->code);
2449 else if (error->domain == GST_CORE_ERROR)
2450 ret = __mmplayer_gst_handle_core_error(player, error->code);
2452 g_error_free(error);
2454 player->msg_posted = TRUE;
2456 gst_message_unref(msg);
2458 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
2460 gst_object_unref(bus);
2461 g_timer_stop(timer);
2462 g_timer_destroy(timer);
2466 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
2467 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
2469 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
2472 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
2476 /* generate dot file before returning error */
2477 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
2484 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
2486 int ret = MM_ERROR_NONE;
2491 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
2492 MM_ERROR_PLAYER_NOT_INITIALIZED);
2494 LOGD("current state before doing transition");
2495 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2496 MMPLAYER_PRINT_STATE(player);
2499 LOGD("do async state transition to PLAYING");
2501 /* set pipeline state to PLAYING */
2502 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2504 ret = __mmplayer_gst_set_state(player,
2505 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
2506 if (ret != MM_ERROR_NONE) {
2507 LOGE("failed to set state to PLAYING");
2511 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2515 /* generate dot file */
2516 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
2523 /* sending event to one of sinkelements */
2525 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
2527 GstEvent * event2 = NULL;
2528 GList *sinks = NULL;
2529 gboolean res = FALSE;
2532 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2533 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
2535 /* While adding subtitles in live feeds seek is getting called.
2536 Adding defensive check in framework layer.*/
2537 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2538 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
2539 LOGE("Should not send seek event during live playback");
2544 if (player->play_subtitle)
2545 event2 = gst_event_copy((const GstEvent *)event);
2547 sinks = player->sink_elements;
2549 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
2551 if (GST_IS_ELEMENT(sink)) {
2552 /* keep ref to the event */
2553 gst_event_ref(event);
2555 if ((res = gst_element_send_event(sink, event))) {
2556 LOGD("sending event[%s] to sink element [%s] success!\n",
2557 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2559 /* rtsp case, asyn_done is not called after seek during pause state */
2560 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2561 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2562 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
2563 LOGD("RTSP seek completed, after pause state..\n");
2564 player->seek_state = MMPLAYER_SEEK_NONE;
2565 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2571 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2572 sinks = g_list_next(sinks);
2579 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
2580 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2583 sinks = g_list_next(sinks);
2586 /* Note : Textbin is not linked to the video or audio bin.
2587 * It needs to send the event to the text sink seperatelly.
2589 if (player->play_subtitle && player->pipeline) {
2590 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
2592 if (GST_IS_ELEMENT(text_sink)) {
2593 /* keep ref to the event */
2594 gst_event_ref(event2);
2596 if ((res = gst_element_send_event(text_sink, event2)))
2597 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
2598 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2600 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
2601 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2603 gst_event_unref(event2);
2607 gst_event_unref(event);
2615 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
2616 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
2617 gint64 cur, GstSeekType stop_type, gint64 stop)
2619 GstEvent* event = NULL;
2620 gboolean result = FALSE;
2624 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2626 if (player->pipeline && player->pipeline->textbin)
2627 __mmplayer_drop_subtitle(player, FALSE);
2629 event = gst_event_new_seek(rate, format, flags, cur_type,
2630 cur, stop_type, stop);
2632 result = __mmplayer_gst_send_event_to_sink(player, event);
2640 __mmplayer_gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
2642 gint64 dur_nsec = 0;
2643 gint64 pos_nsec = 0;
2644 gboolean ret = TRUE;
2645 gboolean accurated = FALSE;
2646 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
2649 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2650 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
2652 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
2653 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
2656 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2657 /* check duration */
2658 /* NOTE : duration cannot be zero except live streaming.
2659 * Since some element could have some timing problemn with quering duration, try again.
2661 if (player->duration == 0) {
2662 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2663 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2664 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2665 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2666 player->pending_seek.is_pending = TRUE;
2667 player->pending_seek.format = format;
2668 player->pending_seek.pos = position;
2669 player->seek_state = MMPLAYER_SEEK_NONE;
2670 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2671 return MM_ERROR_NONE;
2676 player->duration = dur_nsec;
2679 LOGD("playback rate: %f\n", player->playback_rate);
2681 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
2683 seek_flags |= GST_SEEK_FLAG_ACCURATE;
2685 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
2689 case MM_PLAYER_POS_FORMAT_TIME:
2691 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2692 GstQuery *query = NULL;
2693 gboolean seekable = FALSE;
2695 /* check position is valid or not */
2696 if (position > player->duration)
2699 query = gst_query_new_seeking(GST_FORMAT_TIME);
2700 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2701 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2702 gst_query_unref(query);
2705 LOGW("non-seekable content");
2706 player->seek_state = MMPLAYER_SEEK_NONE;
2707 return MM_ERROR_PLAYER_NO_OP;
2710 LOGW("failed to get seeking query");
2711 gst_query_unref(query); /* keep seeking operation */
2714 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
2716 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
2717 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
2718 This causes problem is position calculation during normal pause resume scenarios also.
2719 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
2720 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2721 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2722 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
2723 LOGW("getting current position failed in seek\n");
2725 player->last_position = pos_nsec;
2726 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
2729 if (player->seek_state != MMPLAYER_SEEK_NONE) {
2730 LOGD("not completed seek");
2731 return MM_ERROR_PLAYER_DOING_SEEK;
2735 if (!internal_called)
2736 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2738 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
2739 gint64 cur_time = 0;
2741 /* get current position */
2742 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
2745 GstEvent *event = gst_event_new_seek(1.0,
2747 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
2748 GST_SEEK_TYPE_SET, cur_time,
2749 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2751 __mmplayer_gst_send_event_to_sink(player, event);
2753 if (!MMPLAYER_IS_RTSP_STREAMING(player))
2754 __mmplayer_gst_pause(player, FALSE);
2757 pos_nsec = position;
2759 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
2760 that's why set position through property. */
2761 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2762 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
2763 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
2764 (!player->videodec_linked) && (!player->audiodec_linked)) {
2766 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
2767 LOGD("[%s] set position =%"GST_TIME_FORMAT,
2768 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
2769 player->seek_state = MMPLAYER_SEEK_NONE;
2770 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2772 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2773 GST_FORMAT_TIME, seek_flags,
2774 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2778 LOGE("failed to set position.");
2784 case MM_PLAYER_POS_FORMAT_PERCENT:
2786 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
2788 if (player->seek_state != MMPLAYER_SEEK_NONE) {
2789 LOGD("not completed seek");
2790 return MM_ERROR_PLAYER_DOING_SEEK;
2793 if (!internal_called)
2794 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2796 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
2797 pos_nsec = (gint64)((position * player->duration) / 100);
2798 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2799 GST_FORMAT_TIME, seek_flags,
2800 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2802 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
2812 /* NOTE : store last seeking point to overcome some bad operation
2813 * (returning zero when getting current position) of some elements
2815 player->last_position = pos_nsec;
2817 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
2818 if (player->playback_rate > 1.0)
2819 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
2821 if ((!internal_called) &&
2822 (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
2823 LOGD("buffering should be reset after seeking");
2824 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
2825 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
2829 return MM_ERROR_NONE;
2832 player->pending_seek.is_pending = TRUE;
2833 player->pending_seek.format = format;
2834 player->pending_seek.pos = position;
2836 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
2837 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
2838 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
2839 player->pending_seek.pos);
2841 return MM_ERROR_NONE;
2844 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
2845 return MM_ERROR_INVALID_ARGUMENT;
2848 player->seek_state = MMPLAYER_SEEK_NONE;
2849 return MM_ERROR_PLAYER_SEEK;
2853 __mmplayer_gst_get_position(mm_player_t* player, int format, gint64* position)
2855 #define TRICKPLAY_OFFSET GST_MSECOND
2857 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
2858 gint64 pos_nsec = 0;
2859 gboolean ret = TRUE;
2861 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
2862 MM_ERROR_PLAYER_NOT_INITIALIZED);
2864 current_state = MMPLAYER_CURRENT_STATE(player);
2866 /* NOTE : query position except paused state to overcome some bad operation
2867 * please refer to below comments in details
2869 if (current_state != MM_PLAYER_STATE_PAUSED)
2870 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
2872 /* NOTE : get last point to overcome some bad operation of some elements
2873 *(returning zero when getting current position in paused state
2874 * and when failed to get postion during seeking
2876 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
2877 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
2879 if (player->playback_rate < 0.0)
2880 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
2882 pos_nsec = player->last_position;
2885 pos_nsec = player->last_position;
2887 player->last_position = pos_nsec;
2889 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
2892 if (player->duration > 0 && pos_nsec > player->duration)
2893 pos_nsec = player->duration;
2895 player->last_position = pos_nsec;
2899 case MM_PLAYER_POS_FORMAT_TIME:
2900 *position = pos_nsec;
2903 case MM_PLAYER_POS_FORMAT_PERCENT:
2905 if (player->duration <= 0) {
2906 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
2909 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
2910 *position = (gint64)(pos_nsec * 100 / player->duration);
2915 return MM_ERROR_PLAYER_INTERNAL;
2918 return MM_ERROR_NONE;
2921 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
2923 #define STREAMING_IS_FINISHED 0
2924 #define BUFFERING_MAX_PER 100
2925 #define DEFAULT_PER_VALUE -1
2926 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
2928 MMPlayerGstElement *mainbin = NULL;
2929 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
2930 gint64 buffered_total = 0;
2931 gint64 position = 0;
2932 gint buffered_sec = -1;
2933 GstBufferingMode mode = GST_BUFFERING_STREAM;
2934 gint64 content_size_time = player->duration;
2935 guint64 content_size_bytes = player->http_content_size;
2937 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2939 player->pipeline->mainbin,
2940 MM_ERROR_PLAYER_NOT_INITIALIZED);
2942 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
2947 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
2948 /* and rtsp is not ready yet. */
2949 LOGW("it's only used for http streaming case.\n");
2950 return MM_ERROR_PLAYER_NO_OP;
2953 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
2954 LOGW("Time format is not supported yet.\n");
2955 return MM_ERROR_INVALID_ARGUMENT;
2958 if (content_size_time <= 0 || content_size_bytes <= 0) {
2959 LOGW("there is no content size.");
2960 return MM_ERROR_NONE;
2963 if (__mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
2964 LOGW("fail to get current position.");
2965 return MM_ERROR_NONE;
2968 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
2969 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
2971 mainbin = player->pipeline->mainbin;
2972 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
2974 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
2975 GstQuery *query = NULL;
2976 gint byte_in_rate = 0, byte_out_rate = 0;
2977 gint64 estimated_total = 0;
2979 query = gst_query_new_buffering(GST_FORMAT_BYTES);
2980 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
2981 LOGW("fail to get buffering query from queue2");
2983 gst_query_unref(query);
2984 return MM_ERROR_NONE;
2987 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
2988 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
2990 if (mode == GST_BUFFERING_STREAM) {
2991 /* using only queue in case of push mode(ts / mp3) */
2992 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
2993 GST_FORMAT_BYTES, &buffered_total)) {
2994 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
2995 stop_per = 100 * buffered_total / content_size_bytes;
2998 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3000 guint num_of_ranges = 0;
3001 gint64 start_byte = 0, stop_byte = 0;
3003 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3004 if (estimated_total != STREAMING_IS_FINISHED) {
3005 /* buffered size info from queue2 */
3006 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3007 for (idx = 0; idx < num_of_ranges; idx++) {
3008 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3009 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3011 buffered_total += (stop_byte - start_byte);
3014 stop_per = BUFFERING_MAX_PER;
3016 gst_query_unref(query);
3019 if (stop_per == DEFAULT_PER_VALUE) {
3020 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3022 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3024 /* buffered size info from multiqueue */
3025 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3026 guint curr_size_bytes = 0;
3027 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3028 "curr-size-bytes", &curr_size_bytes, NULL);
3029 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3030 buffered_total += curr_size_bytes;
3033 if (avg_byterate > 0)
3034 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3035 else if (player->total_maximum_bitrate > 0)
3036 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3037 else if (player->total_bitrate > 0)
3038 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3040 if (buffered_sec >= 0)
3041 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3045 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3046 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3048 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
3049 buffered_total, buffered_sec, *start_pos, *stop_pos);
3051 return MM_ERROR_NONE;