4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
87 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
91 count = gst_tag_list_get_tag_size(list, tag);
93 LOGD("count = %d", count);
95 for (i = 0; i < count; i++) {
98 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
99 if (!gst_tag_list_get_string_index(list, tag, i, &str))
100 g_assert_not_reached();
102 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
106 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
108 g_print(" : %s", str);
116 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
118 /* check whether the error is posted from not-activated track or not */
120 gint active_pad_index = 0;
122 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
124 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
125 LOGD("current active pad index -%d", active_pad_index);
127 if (src_element_name) {
130 if (player->audio_decoders) {
131 GList *adec = player->audio_decoders;
132 for (; adec ; adec = g_list_next(adec)) {
133 gchar *name = adec->data;
135 LOGD("found audio decoder name = %s", name);
136 if (g_strrstr(name, src_element_name)) {
143 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
146 if (active_pad_index != msg_src_pos) {
147 LOGD("skip error because error is posted from no activated track");
155 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
157 /* Demuxer can't parse one track because it's corrupted.
158 * So, the decoder for it is not linked.
159 * But, it has one playable track.
161 if (g_strrstr(klass, "Demux")) {
162 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
167 if (player->pipeline->audiobin) { // PCM
168 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
170 LOGD("not found any available codec. Player should be destroyed.");
171 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
176 return MM_ERROR_PLAYER_INVALID_STREAM;
180 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
182 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
183 LOGE("Not supported subtitle.");
184 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
186 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
190 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
192 /* Decoder Custom Message */
193 if (!strstr(error->message, "ongoing"))
194 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
196 if (strncasecmp(klass, "audio", 5)) {
197 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
198 LOGD("Video can keep playing.");
199 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
201 } else if (strncasecmp(klass, "video", 5)) {
202 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
203 LOGD("Audio can keep playing.");
204 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
208 LOGD("not found any available codec. Player should be destroyed.");
209 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
213 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
215 if (strstr(error->message, "rights expired"))
216 return MM_ERROR_PLAYER_DRM_EXPIRED;
217 else if (strstr(error->message, "no rights"))
218 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219 else if (strstr(error->message, "has future rights"))
220 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221 else if (strstr(error->message, "opl violation"))
222 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
224 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
227 /* NOTE : decide gstreamer state whether there is some playable track or not. */
229 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
231 gchar *src_element_name = NULL;
232 GstElement *src_element = NULL;
233 GstElementFactory *factory = NULL;
234 const gchar *klass = NULL;
238 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
239 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
240 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
241 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
243 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
245 src_element = GST_ELEMENT_CAST(message->src);
247 return MM_ERROR_PLAYER_INTERNAL;
249 src_element_name = GST_ELEMENT_NAME(src_element);
250 if (!src_element_name)
251 return MM_ERROR_PLAYER_INTERNAL;
253 factory = gst_element_get_factory(src_element);
255 return MM_ERROR_PLAYER_INTERNAL;
257 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
259 return MM_ERROR_PLAYER_INTERNAL;
261 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
262 error->code, error->message, src_element_name, klass);
264 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
265 return MM_ERROR_NONE;
267 switch (error->code) {
268 case GST_STREAM_ERROR_DECODE:
269 return __mmplayer_gst_transform_error_decode(player, klass);
270 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
271 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
272 case GST_STREAM_ERROR_WRONG_TYPE:
273 return __mmplayer_gst_transform_error_type(player, src_element);
274 case GST_STREAM_ERROR_FAILED:
275 return __mmplayer_gst_transform_error_failed(player, klass, error);
276 case GST_STREAM_ERROR_DECRYPT:
277 case GST_STREAM_ERROR_DECRYPT_NOKEY:
278 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
279 return __mmplayer_gst_transform_error_decrypt(player, error);
286 return MM_ERROR_PLAYER_INVALID_STREAM;
290 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
292 gint trans_err = MM_ERROR_NONE;
296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
299 case GST_CORE_ERROR_MISSING_PLUGIN:
300 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
301 case GST_CORE_ERROR_STATE_CHANGE:
302 case GST_CORE_ERROR_SEEK:
303 case GST_CORE_ERROR_NOT_IMPLEMENTED:
304 case GST_CORE_ERROR_FAILED:
305 case GST_CORE_ERROR_TOO_LAZY:
306 case GST_CORE_ERROR_PAD:
307 case GST_CORE_ERROR_THREAD:
308 case GST_CORE_ERROR_NEGOTIATION:
309 case GST_CORE_ERROR_EVENT:
310 case GST_CORE_ERROR_CAPS:
311 case GST_CORE_ERROR_TAG:
312 case GST_CORE_ERROR_CLOCK:
313 case GST_CORE_ERROR_DISABLED:
315 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
325 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
327 gint trans_err = MM_ERROR_NONE;
331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
334 case GST_LIBRARY_ERROR_FAILED:
335 case GST_LIBRARY_ERROR_TOO_LAZY:
336 case GST_LIBRARY_ERROR_INIT:
337 case GST_LIBRARY_ERROR_SHUTDOWN:
338 case GST_LIBRARY_ERROR_SETTINGS:
339 case GST_LIBRARY_ERROR_ENCODE:
341 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
351 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
353 gint trans_err = MM_ERROR_NONE;
357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
360 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
361 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
363 case GST_RESOURCE_ERROR_NOT_FOUND:
364 case GST_RESOURCE_ERROR_OPEN_READ:
365 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
366 || MMPLAYER_IS_RTSP_STREAMING(player)) {
367 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
370 case GST_RESOURCE_ERROR_READ:
371 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
372 || MMPLAYER_IS_RTSP_STREAMING(player)) {
373 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
375 } else if (message != NULL && message->src != NULL) {
376 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
377 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
379 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
380 path_type = MMPLAYER_PATH_VOD;
381 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
382 path_type = MMPLAYER_PATH_TEXT;
384 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
385 /* check storage state */
386 storage_get_state(player->storage_info[path_type].id, &storage_state);
387 player->storage_info[path_type].state = storage_state;
388 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
391 case GST_RESOURCE_ERROR_WRITE:
392 case GST_RESOURCE_ERROR_FAILED:
393 case GST_RESOURCE_ERROR_SEEK:
394 case GST_RESOURCE_ERROR_TOO_LAZY:
395 case GST_RESOURCE_ERROR_BUSY:
396 case GST_RESOURCE_ERROR_OPEN_WRITE:
397 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
398 case GST_RESOURCE_ERROR_CLOSE:
399 case GST_RESOURCE_ERROR_SYNC:
400 case GST_RESOURCE_ERROR_SETTINGS:
402 trans_err = MM_ERROR_PLAYER_INTERNAL;
412 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
414 gint trans_err = MM_ERROR_NONE;
418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
419 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
420 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
422 switch (error->code) {
423 case GST_STREAM_ERROR_FAILED:
424 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
425 case GST_STREAM_ERROR_DECODE:
426 case GST_STREAM_ERROR_WRONG_TYPE:
427 case GST_STREAM_ERROR_DECRYPT:
428 case GST_STREAM_ERROR_DECRYPT_NOKEY:
429 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
430 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
433 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
434 case GST_STREAM_ERROR_TOO_LAZY:
435 case GST_STREAM_ERROR_ENCODE:
436 case GST_STREAM_ERROR_DEMUX:
437 case GST_STREAM_ERROR_MUX:
438 case GST_STREAM_ERROR_FORMAT:
440 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
450 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
452 MMMessageParamType msg_param;
453 gchar *msg_src_element;
457 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
458 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
460 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
462 memset(&msg_param, 0, sizeof(MMMessageParamType));
464 if (error->domain == GST_CORE_ERROR) {
465 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
466 } else if (error->domain == GST_LIBRARY_ERROR) {
467 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
468 } else if (error->domain == GST_RESOURCE_ERROR) {
469 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
470 } else if (error->domain == GST_STREAM_ERROR) {
471 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
473 LOGW("This error domain is not defined.");
475 /* we treat system error as an internal error */
476 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
480 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
482 msg_param.data = (void *)error->message;
484 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
485 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
489 if (msg_param.code == MM_ERROR_NONE)
492 /* skip error to avoid duplicated posting */
493 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
494 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
495 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
496 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
498 /* The error will be handled by mused.
499 * @ref _mmplayer_manage_external_storage_state() */
501 LOGW("storage is removed, skip error post");
505 /* post error to application */
506 if (!player->msg_posted) {
507 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
508 /* don't post more if one was sent already */
509 player->msg_posted = TRUE;
511 LOGD("skip error post because it's sent already.");
520 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
523 MMMessageParamType msg_param;
524 gchar *msg_src_element = NULL;
525 GstStructure *s = NULL;
527 gchar *error_string = NULL;
531 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
532 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
534 s = gst_structure_copy(gst_message_get_structure(message));
537 if (!gst_structure_get_uint(s, "error_id", &error_id))
538 error_id = MMPLAYER_STREAMING_ERROR_NONE;
541 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
542 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
544 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
545 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
547 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
548 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
550 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
551 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
553 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
554 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
556 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
557 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
559 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
560 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
562 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
563 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
565 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
566 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
568 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
569 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
571 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
572 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
574 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
575 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
577 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
578 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
580 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
581 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
583 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
584 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
586 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
587 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
589 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
590 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
592 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
593 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
595 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
596 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
598 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
599 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
601 case MMPLAYER_STREAMING_ERROR_GONE:
602 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
604 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
605 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
607 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
608 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
610 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
611 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
613 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
614 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
616 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
617 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
619 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
620 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
622 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
623 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
625 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
626 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
628 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
629 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
631 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
632 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
634 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
635 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
637 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
638 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
640 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
641 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
643 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
644 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
646 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
647 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
649 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
650 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
652 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
653 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
655 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
656 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
658 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
659 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
661 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
662 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
664 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
665 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
667 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
668 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
670 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
671 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
673 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
674 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
678 gst_structure_free(s);
679 return MM_ERROR_PLAYER_STREAMING_FAIL;
683 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
685 msg_param.data = (void *)error_string;
688 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
690 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]",
691 msg_src_element, msg_param.code, (char *)msg_param.data);
694 /* post error to application */
695 if (!player->msg_posted) {
696 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
698 /* don't post more if one was sent already */
699 player->msg_posted = TRUE;
701 LOGD("skip error post because it's sent already.");
704 gst_structure_free(s);
705 MMPLAYER_FREEIF(error_string);
713 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
715 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
716 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
717 gst_tag_list_get_string(tags, "stitching_software",
718 &metadata->stitching_software);
719 gst_tag_list_get_string(tags, "projection_type",
720 &metadata->projection_type_string);
721 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
722 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
723 gst_tag_list_get_int(tags, "init_view_heading",
724 &metadata->init_view_heading);
725 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
726 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
727 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
728 gst_tag_list_get_int(tags, "full_pano_width_pixels",
729 &metadata->full_pano_width_pixels);
730 gst_tag_list_get_int(tags, "full_pano_height_pixels",
731 &metadata->full_pano_height_pixels);
732 gst_tag_list_get_int(tags, "cropped_area_image_width",
733 &metadata->cropped_area_image_width);
734 gst_tag_list_get_int(tags, "cropped_area_image_height",
735 &metadata->cropped_area_image_height);
736 gst_tag_list_get_int(tags, "cropped_area_left",
737 &metadata->cropped_area_left);
738 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
739 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
740 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
741 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
745 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
748 /* macro for better code readability */
749 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
751 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
752 if (string != NULL) { \
753 SECURE_LOGD("update tag string : %s", string); \
754 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
755 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
756 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
757 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
758 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
759 MMPLAYER_FREEIF(new_string); \
761 mm_attrs_set_string_by_name(attribute, playertag, string); \
763 MMPLAYER_FREEIF(string); \
768 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
770 GstSample *sample = NULL;\
771 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
772 GstMapInfo info = GST_MAP_INFO_INIT;\
773 buffer = gst_sample_get_buffer(sample);\
774 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
775 LOGD("failed to get image data from tag");\
776 gst_sample_unref(sample);\
779 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
780 MMPLAYER_FREEIF(player->album_art);\
781 player->album_art = (gchar *)g_malloc(info.size);\
782 if (player->album_art) {\
783 memcpy(player->album_art, info.data, info.size);\
784 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
785 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
786 msg_param.data = (void *)player->album_art;\
787 msg_param.size = info.size;\
788 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
789 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
792 gst_buffer_unmap(buffer, &info);\
793 gst_sample_unref(sample);\
797 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
799 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
802 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
803 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
804 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
805 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
806 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
808 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
809 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
810 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
811 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
812 player->bitrate[track_type] = v_uint; \
813 player->total_bitrate = 0; \
814 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
815 player->total_bitrate += player->bitrate[i]; \
816 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
817 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
818 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
819 player->maximum_bitrate[track_type] = v_uint; \
820 player->total_maximum_bitrate = 0; \
821 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
822 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
823 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
824 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
826 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
833 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
835 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
837 string = g_strdup_printf("%d", g_date_get_year(date));\
838 mm_attrs_set_string_by_name(attribute, playertag, string);\
839 SECURE_LOGD("metainfo year : %s", string);\
840 MMPLAYER_FREEIF(string);\
846 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
848 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
849 if (datetime != NULL) {\
850 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
851 mm_attrs_set_string_by_name(attribute, playertag, string);\
852 SECURE_LOGD("metainfo year : %s", string);\
853 MMPLAYER_FREEIF(string);\
854 gst_date_time_unref(datetime);\
859 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
861 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
863 /* FIXIT : don't know how to store date */\
870 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
872 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
874 /* FIXIT : don't know how to store date */\
882 GstTagList *tag_list = NULL;
884 MMHandleType attrs = 0;
889 GstDateTime *datetime = NULL;
891 GstBuffer *buffer = NULL;
893 MMMessageParamType msg_param = {0, };
895 /* currently not used. but those are needed for above macro */
896 //guint64 v_uint64 = 0;
897 //gdouble v_double = 0;
899 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
901 attrs = MMPLAYER_GET_ATTRS(player);
903 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
905 /* get tag list from gst message */
906 gst_message_parse_tag(msg, &tag_list);
908 /* store tags to player attributes */
909 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
910 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
911 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
912 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
913 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
915 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
916 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
917 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
918 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
920 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
921 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
922 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
923 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
924 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
925 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
926 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
927 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
928 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
929 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
930 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
931 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
932 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
933 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
936 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
937 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
938 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
939 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
940 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
941 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
942 MMPLAYER_UPDATE_TAG_LOCK(player);
943 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
944 MMPLAYER_UPDATE_TAG_UNLOCK(player);
945 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
946 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
947 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
948 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
949 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
950 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
951 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
952 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
953 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
954 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
955 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
956 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
957 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
959 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
960 if (player->video360_metadata.is_spherical == -1) {
961 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
962 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
963 player->video360_metadata.is_spherical);
964 if (player->video360_metadata.is_spherical == 1) {
965 LOGD("This is spherical content for 360 playback.");
966 player->is_content_spherical = TRUE;
968 LOGD("This is not spherical content");
969 player->is_content_spherical = FALSE;
972 if (player->video360_metadata.projection_type_string) {
973 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
974 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
976 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
977 player->is_content_spherical = player->is_video360_enabled = FALSE;
981 if (player->video360_metadata.stereo_mode_string) {
982 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
983 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
984 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
985 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
986 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
987 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
989 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
990 player->is_content_spherical = player->is_video360_enabled = FALSE;
996 if (mm_attrs_commit_all(attrs))
997 LOGE("failed to commit.");
999 gst_tag_list_unref(tag_list);
1004 /* if retval is FALSE, it will be dropped for perfomance. */
1006 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
1008 gboolean retval = FALSE;
1010 if (!(player->pipeline && player->pipeline->mainbin)) {
1011 LOGE("player pipeline handle is null");
1015 switch (GST_MESSAGE_TYPE(message)) {
1016 case GST_MESSAGE_TAG:
1017 case GST_MESSAGE_EOS:
1018 case GST_MESSAGE_ERROR:
1019 case GST_MESSAGE_WARNING:
1020 case GST_MESSAGE_CLOCK_LOST:
1021 case GST_MESSAGE_NEW_CLOCK:
1022 case GST_MESSAGE_ELEMENT:
1023 case GST_MESSAGE_DURATION_CHANGED:
1024 case GST_MESSAGE_ASYNC_START:
1027 case GST_MESSAGE_ASYNC_DONE:
1028 case GST_MESSAGE_STATE_CHANGED:
1029 /* we only handle messages from pipeline */
1030 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
1035 case GST_MESSAGE_BUFFERING:
1037 gint buffer_percent = 0;
1040 gst_message_parse_buffering(message, &buffer_percent);
1041 if (buffer_percent != MAX_BUFFER_PERCENT) {
1042 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1046 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1047 LOGW("can't get cmd lock, send msg to bus");
1051 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1052 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1053 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1056 MMPLAYER_CMD_UNLOCK(player);
1069 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1071 guint64 data_size = 0;
1072 gint64 pos_nsec = 0;
1074 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1076 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1078 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1079 data_size = player->http_content_size;
1082 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1083 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1089 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1091 int ret = MM_ERROR_NONE;
1092 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1093 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1094 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1095 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1097 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1098 LOGW("do nothing for buffering msg");
1099 ret = MM_ERROR_PLAYER_INVALID_STATE;
1103 prev_state = MMPLAYER_PREV_STATE(player);
1104 current_state = MMPLAYER_CURRENT_STATE(player);
1105 target_state = MMPLAYER_TARGET_STATE(player);
1106 pending_state = MMPLAYER_PENDING_STATE(player);
1108 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1109 MMPLAYER_STATE_GET_NAME(prev_state),
1110 MMPLAYER_STATE_GET_NAME(current_state),
1111 MMPLAYER_STATE_GET_NAME(pending_state),
1112 MMPLAYER_STATE_GET_NAME(target_state),
1113 player->streamer->buffering_state);
1115 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1116 /* NOTE : if buffering has done, player has to go to target state. */
1117 switch (target_state) {
1118 case MM_PLAYER_STATE_PAUSED:
1120 switch (pending_state) {
1121 case MM_PLAYER_STATE_PLAYING:
1122 _mmplayer_gst_pause(player, TRUE);
1125 case MM_PLAYER_STATE_PAUSED:
1126 LOGD("player is already going to paused state, there is nothing to do.");
1129 case MM_PLAYER_STATE_NONE:
1130 case MM_PLAYER_STATE_NULL:
1131 case MM_PLAYER_STATE_READY:
1133 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1139 case MM_PLAYER_STATE_PLAYING:
1141 switch (pending_state) {
1142 case MM_PLAYER_STATE_NONE:
1144 if (current_state != MM_PLAYER_STATE_PLAYING)
1145 _mmplayer_gst_resume(player, TRUE);
1149 case MM_PLAYER_STATE_PAUSED:
1150 /* NOTE: It should be worked as asynchronously.
1151 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1153 if (current_state == MM_PLAYER_STATE_PLAYING) {
1154 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1155 * The current state should be changed to paused purposely to prevent state conflict.
1157 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1159 _mmplayer_gst_resume(player, TRUE);
1162 case MM_PLAYER_STATE_PLAYING:
1163 LOGD("player is already going to playing state, there is nothing to do.");
1166 case MM_PLAYER_STATE_NULL:
1167 case MM_PLAYER_STATE_READY:
1169 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1175 case MM_PLAYER_STATE_NULL:
1176 case MM_PLAYER_STATE_READY:
1177 case MM_PLAYER_STATE_NONE:
1179 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1183 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1184 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1186 switch (pending_state) {
1187 case MM_PLAYER_STATE_NONE:
1189 if (current_state != MM_PLAYER_STATE_PAUSED) {
1190 /* rtsp streaming pause makes rtsp server stop sending data. */
1191 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1192 LOGD("set pause state during buffering");
1193 _mmplayer_gst_pause(player, TRUE);
1199 case MM_PLAYER_STATE_PLAYING:
1200 /* rtsp streaming pause makes rtsp server stop sending data. */
1201 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1202 _mmplayer_gst_pause(player, TRUE);
1205 case MM_PLAYER_STATE_PAUSED:
1208 case MM_PLAYER_STATE_NULL:
1209 case MM_PLAYER_STATE_READY:
1211 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1220 static stream_variant_t *
1221 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1223 stream_variant_t *var_info = NULL;
1224 g_return_val_if_fail(self != NULL, NULL);
1226 var_info = g_new0(stream_variant_t, 1);
1227 if (!var_info) return NULL;
1228 var_info->bandwidth = self->bandwidth;
1229 var_info->width = self->width;
1230 var_info->height = self->height;
1235 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1241 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1242 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1244 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1245 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1246 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1248 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1249 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1250 player->http_content_size = (bytes > 0) ? bytes : 0;
1253 /* handling audio clip which has vbr. means duration is keep changing */
1254 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1263 __mmplayer_eos_timer_cb(gpointer u_data)
1265 mmplayer_t *player = NULL;
1266 MMHandleType attrs = 0;
1269 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1271 player = (mmplayer_t *)u_data;
1272 attrs = MMPLAYER_GET_ATTRS(player);
1274 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1278 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1279 if (ret_value != MM_ERROR_NONE)
1280 LOGE("seeking to 0 failed in repeat play");
1283 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1286 /* we are returning FALSE as we need only one posting */
1291 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1293 MMPLAYER_RETURN_IF_FAIL(player);
1295 /* post now if delay is zero */
1296 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1297 LOGD("eos delay is zero. posting EOS now");
1298 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1300 if (player->audio_decoded_cb)
1301 _mmplayer_cancel_eos_timer(player);
1306 /* cancel if existing */
1307 _mmplayer_cancel_eos_timer(player);
1309 /* init new timeout */
1310 /* NOTE : consider give high priority to this timer */
1311 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1313 player->eos_timer = g_timeout_add(delay_in_ms,
1314 __mmplayer_eos_timer_cb, player);
1316 player->context.global_default = g_main_context_default();
1317 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1319 /* check timer is valid. if not, send EOS now */
1320 if (player->eos_timer == 0) {
1321 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1322 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1327 __mmplayer_gst_pending_seek(mmplayer_t *player)
1329 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1330 int ret = MM_ERROR_NONE;
1334 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1336 if (!player->pending_seek.is_pending) {
1337 LOGD("pending seek is not reserved. nothing to do.");
1341 /* check player state if player could pending seek or not. */
1342 current_state = MMPLAYER_CURRENT_STATE(player);
1344 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1345 LOGW("try to pending seek in %s state, try next time. ",
1346 MMPLAYER_STATE_GET_NAME(current_state));
1350 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1352 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1353 if (ret != MM_ERROR_NONE)
1354 LOGE("failed to seek pending postion. just keep staying current position.");
1356 player->pending_seek.is_pending = false;
1364 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1366 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1368 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1370 audiobin = player->pipeline->audiobin; /* can be null */
1371 videobin = player->pipeline->videobin; /* can be null */
1372 textbin = player->pipeline->textbin; /* can be null */
1374 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1376 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1377 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1379 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1380 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1382 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1383 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1389 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1391 mmplayer_gst_element_t *textbin;
1394 MMPLAYER_RETURN_IF_FAIL(player &&
1396 player->pipeline->textbin);
1398 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1400 textbin = player->pipeline->textbin;
1403 LOGD("Drop subtitle text after getting EOS");
1405 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1406 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1408 player->is_subtitle_force_drop = TRUE;
1410 if (player->is_subtitle_force_drop == TRUE) {
1411 LOGD("Enable subtitle data path without drop");
1413 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1414 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1416 LOGD("non-connected with external display");
1418 player->is_subtitle_force_drop = FALSE;
1424 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1426 MMHandleType attrs = 0;
1431 /* NOTE : EOS event is comming multiple time. watch out it */
1432 /* check state. we only process EOS when pipeline state goes to PLAYING */
1433 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1434 LOGD("EOS received on non-playing state. ignoring it");
1438 if (player->pipeline && player->pipeline->textbin)
1439 __mmplayer_drop_subtitle(player, TRUE);
1441 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1442 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1444 /* rewind if repeat count is greater then zero */
1445 /* get play count */
1446 attrs = MMPLAYER_GET_ATTRS(player);
1448 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1450 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1452 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1453 if (player->playback_rate < 0.0) {
1454 player->resumed_by_rewind = TRUE;
1455 _mmplayer_set_mute((MMHandleType)player, false);
1456 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1459 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1462 player->sent_bos = FALSE;
1464 LOGD("do not post eos msg for repeating");
1469 if (player->pipeline)
1470 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1472 /* post eos message to application */
1473 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1475 /* reset last position */
1476 player->last_position = 0;
1483 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1485 GError *error = NULL;
1486 gchar *debug = NULL;
1490 /* generating debug info before returning error */
1491 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1493 /* get error code */
1494 gst_message_parse_error(msg, &error, &debug);
1496 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1497 /* Note : the streaming error from the streaming source is handled
1498 * using __mmplayer_handle_streaming_error.
1500 __mmplayer_handle_streaming_error(player, msg);
1502 /* dump state of all element */
1503 _mmplayer_dump_pipeline_state(player);
1505 /* traslate gst error code to msl error code. then post it
1506 * to application if needed
1508 __mmplayer_handle_gst_error(player, msg, error);
1511 LOGE("error debug : %s", debug);
1514 MMPLAYER_FREEIF(debug);
1515 g_error_free(error);
1522 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1524 MMMessageParamType msg_param = {0, };
1525 int bRet = MM_ERROR_NONE;
1528 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1530 if (!MMPLAYER_IS_STREAMING(player)) {
1531 LOGW("this is not streaming playback.");
1535 MMPLAYER_CMD_LOCK(player);
1537 if (!player->streamer) {
1538 LOGW("Pipeline is shutting down");
1539 MMPLAYER_CMD_UNLOCK(player);
1543 /* ignore the remained buffering message till getting 100% msg */
1544 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1545 gint buffer_percent = 0;
1547 gst_message_parse_buffering(msg, &buffer_percent);
1549 if (buffer_percent == MAX_BUFFER_PERCENT) {
1550 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1551 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1552 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1554 MMPLAYER_CMD_UNLOCK(player);
1558 /* ignore the remained buffering message */
1559 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1560 gint buffer_percent = 0;
1562 gst_message_parse_buffering(msg, &buffer_percent);
1564 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1565 player->streamer->buffering_percent, buffer_percent);
1567 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1568 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1569 player->streamer->buffering_req.is_pre_buffering = FALSE;
1571 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1573 LOGD("interrupted buffering - ignored the remained buffering msg!");
1574 MMPLAYER_CMD_UNLOCK(player);
1579 __mmplayer_update_buffer_setting(player, msg);
1581 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1583 if (bRet == MM_ERROR_NONE) {
1584 msg_param.connection.buffering = player->streamer->buffering_percent;
1585 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1587 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1588 player->pending_resume &&
1589 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1591 player->is_external_subtitle_added_now = FALSE;
1592 player->pending_resume = FALSE;
1593 _mmplayer_resume((MMHandleType)player);
1596 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1597 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1599 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1600 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1601 player->seek_state = MMPLAYER_SEEK_NONE;
1602 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1603 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1604 /* Considering the async state trasition in case of RTSP.
1605 After getting state change gst msg, seek cmpleted msg will be posted. */
1606 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1610 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1611 if (!player->streamer) {
1612 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1613 MMPLAYER_CMD_UNLOCK(player);
1617 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1619 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1620 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1622 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1623 msg_param.connection.buffering = player->streamer->buffering_percent;
1624 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1626 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1629 msg_param.connection.buffering = player->streamer->buffering_percent;
1630 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1633 MMPLAYER_CMD_UNLOCK(player);
1641 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1643 mmplayer_gst_element_t *mainbin;
1644 const GValue *voldstate, *vnewstate, *vpending;
1645 GstState oldstate = GST_STATE_NULL;
1646 GstState newstate = GST_STATE_NULL;
1647 GstState pending = GST_STATE_NULL;
1650 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1652 mainbin = player->pipeline->mainbin;
1654 /* we only handle messages from pipeline */
1655 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1658 /* get state info from msg */
1659 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1660 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1661 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1663 if (!voldstate || !vnewstate) {
1664 LOGE("received msg has wrong format.");
1668 oldstate = (GstState)voldstate->data[0].v_int;
1669 newstate = (GstState)vnewstate->data[0].v_int;
1671 pending = (GstState)vpending->data[0].v_int;
1673 LOGD("state changed [%s] : %s ---> %s final : %s",
1674 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1675 gst_element_state_get_name((GstState)oldstate),
1676 gst_element_state_get_name((GstState)newstate),
1677 gst_element_state_get_name((GstState)pending));
1679 if (newstate == GST_STATE_PLAYING) {
1680 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1682 int retVal = MM_ERROR_NONE;
1683 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1685 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1687 if (MM_ERROR_NONE != retVal)
1688 LOGE("failed to seek pending postion. just keep staying current position.");
1690 player->pending_seek.is_pending = false;
1694 if (oldstate == newstate) {
1695 LOGD("pipeline reports state transition to old state");
1700 case GST_STATE_PAUSED:
1702 gboolean prepare_async = FALSE;
1704 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1705 // managed prepare async case
1706 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1707 LOGD("checking prepare mode for async transition - %d", prepare_async);
1710 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1711 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1713 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1714 _mm_player_streaming_set_content_bitrate(player->streamer,
1715 player->total_maximum_bitrate, player->total_bitrate);
1717 if (player->pending_seek.is_pending) {
1718 LOGW("trying to do pending seek");
1719 MMPLAYER_CMD_LOCK(player);
1720 __mmplayer_gst_pending_seek(player);
1721 MMPLAYER_CMD_UNLOCK(player);
1727 case GST_STATE_PLAYING:
1729 if (MMPLAYER_IS_STREAMING(player)) {
1730 // managed prepare async case when buffering is completed
1731 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1732 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1733 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1734 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1736 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1738 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1739 if (player->streamer->buffering_percent < 100) {
1741 MMMessageParamType msg_param = {0, };
1742 LOGW("Posting Buffering Completed Message to Application !!!");
1744 msg_param.connection.buffering = 100;
1745 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1750 if (player->gapless.stream_changed) {
1751 _mmplayer_update_content_attrs(player, ATTR_ALL);
1752 player->gapless.stream_changed = FALSE;
1755 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1756 player->seek_state = MMPLAYER_SEEK_NONE;
1757 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1761 case GST_STATE_VOID_PENDING:
1762 case GST_STATE_NULL:
1763 case GST_STATE_READY:
1773 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1775 const gchar *structure_name;
1776 gint count = 0, idx = 0;
1777 MMHandleType attrs = 0;
1780 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1782 attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("Failed to get content attribute");
1788 if (gst_message_get_structure(msg) == NULL)
1791 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1792 if (!structure_name)
1795 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1797 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1798 const GValue *var_info = NULL;
1800 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1801 if (var_info != NULL) {
1802 if (player->adaptive_info.var_list)
1803 g_list_free_full(player->adaptive_info.var_list, g_free);
1805 /* share addr or copy the list */
1806 player->adaptive_info.var_list =
1807 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1809 count = g_list_length(player->adaptive_info.var_list);
1811 stream_variant_t *temp = NULL;
1813 /* print out for debug */
1814 LOGD("num of variant_info %d", count);
1815 for (idx = 0; idx < count; idx++) {
1816 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1818 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1824 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1825 gint num_buffers = 0;
1826 gint extra_num_buffers = 0;
1828 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1829 LOGD("video_num_buffers : %d", num_buffers);
1830 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers);
1833 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1834 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1835 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers);
1840 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1841 _mmplayer_track_update_text_attr_info(player, msg);
1843 /* custom message */
1844 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1845 MMMessageParamType msg_param = {0,};
1846 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1847 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1850 /* custom message for RTSP attribute :
1851 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1852 sdp which has contents info is received when rtsp connection is opened.
1853 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1854 if (!strcmp(structure_name, "rtspsrc_properties")) {
1855 gchar *audio_codec = NULL;
1856 gchar *video_codec = NULL;
1857 gchar *video_frame_size = NULL;
1859 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1860 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1861 player->streaming_type = _mmplayer_get_stream_service_type(player);
1863 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1864 LOGD("rtsp_audio_codec : %s", audio_codec);
1866 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1868 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1869 LOGD("rtsp_video_codec : %s", video_codec);
1871 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1873 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1874 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1875 if (video_frame_size) {
1876 char *seperator = strchr(video_frame_size, '-');
1878 char video_width[10] = {0,};
1879 int frame_size_len = strlen(video_frame_size);
1880 int separtor_len = strlen(seperator);
1882 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1883 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, atoi(video_width));
1886 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, atoi(seperator));
1890 if (mm_attrs_commit_all(attrs))
1891 LOGE("failed to commit.");
1899 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1901 mmplayer_gst_element_t *mainbin;
1904 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1906 mainbin = player->pipeline->mainbin;
1908 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1910 /* we only handle messages from pipeline */
1911 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1914 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1915 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1916 player->seek_state = MMPLAYER_SEEK_NONE;
1917 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1918 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1919 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1920 LOGD("sync %s state(%s) with parent state(%s)",
1921 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1922 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1923 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1925 /* In case of streaming, pause is required before finishing seeking by buffering.
1926 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1927 Because the buffering state is controlled according to the state transition for force resume,
1928 the decodebin state should be paused as player state. */
1929 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1932 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1933 (player->streamer) &&
1934 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1935 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1936 GstQuery *query = NULL;
1937 gboolean busy = FALSE;
1940 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1941 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1942 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1943 gst_query_parse_buffering_percent(query, &busy, &percent);
1944 gst_query_unref(query);
1946 LOGD("buffered percent(%s): %d",
1947 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1951 __mmplayer_handle_buffering_playback(player);
1954 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1963 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1965 mmplayer_t *player = (mmplayer_t *)(data);
1967 MMPLAYER_RETURN_IF_FAIL(player);
1968 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1970 switch (GST_MESSAGE_TYPE(msg)) {
1971 case GST_MESSAGE_UNKNOWN:
1972 LOGD("unknown message received");
1975 case GST_MESSAGE_EOS:
1976 LOGD("GST_MESSAGE_EOS received");
1977 __mmplayer_gst_handle_eos_message(player, msg);
1980 case GST_MESSAGE_ERROR:
1981 __mmplayer_gst_handle_error_message(player, msg);
1984 case GST_MESSAGE_WARNING:
1987 GError *error = NULL;
1989 gst_message_parse_warning(msg, &error, &debug);
1991 LOGD("warning : %s", error->message);
1992 LOGD("debug : %s", debug);
1994 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1996 MMPLAYER_FREEIF(debug);
1997 g_error_free(error);
2001 case GST_MESSAGE_TAG:
2003 LOGD("GST_MESSAGE_TAG");
2004 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2005 LOGW("failed to extract tags from gstmessage");
2009 case GST_MESSAGE_BUFFERING:
2010 __mmplayer_gst_handle_buffering_message(player, msg);
2013 case GST_MESSAGE_STATE_CHANGED:
2014 __mmplayer_gst_handle_state_message(player, msg);
2017 case GST_MESSAGE_CLOCK_LOST:
2019 GstClock *clock = NULL;
2020 gboolean need_new_clock = FALSE;
2022 gst_message_parse_clock_lost(msg, &clock);
2023 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2025 if (!player->videodec_linked)
2026 need_new_clock = TRUE;
2027 else if (!player->ini.use_system_clock)
2028 need_new_clock = TRUE;
2030 if (need_new_clock) {
2031 LOGD("Provide clock is TRUE, do pause->resume");
2032 _mmplayer_gst_pause(player, FALSE);
2033 _mmplayer_gst_resume(player, FALSE);
2038 case GST_MESSAGE_NEW_CLOCK:
2040 GstClock *clock = NULL;
2041 gst_message_parse_new_clock(msg, &clock);
2042 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2046 case GST_MESSAGE_ELEMENT:
2047 __mmplayer_gst_handle_element_message(player, msg);
2050 case GST_MESSAGE_DURATION_CHANGED:
2052 LOGD("GST_MESSAGE_DURATION_CHANGED");
2053 if (!__mmplayer_gst_handle_duration(player, msg))
2054 LOGW("failed to update duration");
2058 case GST_MESSAGE_ASYNC_START:
2059 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2062 case GST_MESSAGE_ASYNC_DONE:
2063 __mmplayer_gst_handle_async_done_message(player, msg);
2067 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2068 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2069 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2070 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2071 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2072 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2073 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2074 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2075 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2076 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2077 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2078 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2079 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2080 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2081 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2088 /* should not call 'gst_message_unref(msg)' */
2092 static GstBusSyncReply
2093 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2095 mmplayer_t *player = (mmplayer_t *)data;
2096 GstBusSyncReply reply = GST_BUS_DROP;
2098 if (!(player->pipeline && player->pipeline->mainbin)) {
2099 LOGE("player pipeline handle is null");
2100 return GST_BUS_PASS;
2103 if (!__mmplayer_gst_check_useful_message(player, message)) {
2104 gst_message_unref(message);
2105 return GST_BUS_DROP;
2108 switch (GST_MESSAGE_TYPE(message)) {
2109 case GST_MESSAGE_TAG:
2110 __mmplayer_gst_extract_tag_from_msg(player, message);
2114 GstTagList *tags = NULL;
2116 gst_message_parse_tag(message, &tags);
2118 LOGE("TAGS received from element \"%s\".",
2119 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2121 gst_tag_list_foreach(tags, print_tag, NULL);
2122 gst_tag_list_unref(tags);
2130 case GST_MESSAGE_DURATION_CHANGED:
2131 __mmplayer_gst_handle_duration(player, message);
2133 case GST_MESSAGE_ASYNC_DONE:
2134 /* NOTE:Don't call gst_callback directly
2135 * because previous frame can be showed even though this message is received for seek.
2138 reply = GST_BUS_PASS;
2142 if (reply == GST_BUS_DROP)
2143 gst_message_unref(message);
2149 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2151 GstElement *appsrc = element;
2152 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2153 GstBuffer *buffer = NULL;
2154 GstFlowReturn ret = GST_FLOW_OK;
2157 MMPLAYER_RETURN_IF_FAIL(element);
2158 MMPLAYER_RETURN_IF_FAIL(buf);
2160 buffer = gst_buffer_new();
2162 if (buf->offset < 0 || buf->len < 0) {
2163 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2167 if (buf->offset >= buf->len) {
2168 LOGD("call eos appsrc");
2169 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2173 if (buf->len - buf->offset < size)
2174 len = buf->len - buf->offset;
2176 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2177 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2178 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2181 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2183 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2189 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2191 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2193 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2195 buf->offset = (int)size;
2201 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2203 mmplayer_t *player = (mmplayer_t *)user_data;
2204 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2205 MMMessageParamType msg_param = {0,};
2206 guint64 current_level_bytes = 0;
2208 MMPLAYER_RETURN_IF_FAIL(player);
2210 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2211 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2212 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2213 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2215 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2219 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2221 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2223 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2224 msg_param.buffer_status.stream_type = stream_type;
2225 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2226 msg_param.buffer_status.bytes = current_level_bytes;
2228 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2232 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2234 mmplayer_t *player = (mmplayer_t *)user_data;
2235 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2236 MMMessageParamType msg_param = {0,};
2237 guint64 current_level_bytes = 0;
2239 MMPLAYER_RETURN_IF_FAIL(player);
2241 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2242 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2243 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2244 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2246 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2250 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2252 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2254 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2255 msg_param.buffer_status.stream_type = stream_type;
2256 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2257 msg_param.buffer_status.bytes = current_level_bytes;
2259 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2263 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2265 mmplayer_t *player = (mmplayer_t *)user_data;
2266 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2267 MMMessageParamType msg_param = {0,};
2269 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2271 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2272 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2273 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2274 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2276 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2280 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2282 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2283 msg_param.seek_data.stream_type = stream_type;
2284 msg_param.seek_data.offset = position;
2286 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2292 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2294 #define MAX_LEN_NAME 20
2296 gboolean ret = FALSE;
2297 GstPad *sinkpad = NULL;
2298 gchar *prefix = NULL;
2299 gchar dec_name[MAX_LEN_NAME] = {0, };
2300 main_element_id_e elem_id = MMPLAYER_M_NUM;
2302 mmplayer_gst_element_t *mainbin = NULL;
2303 GstElement *decodebin = NULL;
2304 GstCaps *dec_caps = NULL;
2308 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2310 player->pipeline->mainbin, FALSE);
2311 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2313 mainbin = player->pipeline->mainbin;
2315 case MM_PLAYER_STREAM_TYPE_AUDIO:
2317 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2319 case MM_PLAYER_STREAM_TYPE_VIDEO:
2321 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2324 LOGE("invalid type %d", type);
2328 if (mainbin[elem_id].gst) {
2329 LOGE("elem(%d) is already created", elem_id);
2333 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2335 /* create decodebin */
2336 decodebin = gst_element_factory_make("decodebin", dec_name);
2338 LOGE("failed to create %s", dec_name);
2342 mainbin[elem_id].id = elem_id;
2343 mainbin[elem_id].gst = decodebin;
2345 /* raw pad handling signal */
2346 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2347 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2349 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2350 before looking for any elements that can handle that stream.*/
2351 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2352 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2354 /* This signal is emitted when a element is added to the bin.*/
2355 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2356 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2358 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2359 LOGE("failed to add new decodebin");
2363 dec_caps = gst_pad_query_caps(srcpad, NULL);
2366 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2368 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2369 gst_caps_unref(dec_caps);
2372 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2374 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2375 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2378 gst_object_unref(GST_OBJECT(sinkpad));
2380 gst_element_sync_state_with_parent(decodebin);
2386 gst_object_unref(GST_OBJECT(sinkpad));
2388 if (mainbin[elem_id].gst) {
2389 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2390 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2391 gst_object_unref(mainbin[elem_id].gst);
2392 mainbin[elem_id].gst = NULL;
2400 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2402 #define MAX_LEN_NAME 20
2403 mmplayer_gst_element_t *mainbin = NULL;
2404 gchar *prefix = NULL;
2405 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2407 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2408 GstElement *src = NULL, *queue = NULL;
2409 GstPad *srcpad = NULL;
2412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2413 player->pipeline->mainbin, FALSE);
2415 mainbin = player->pipeline->mainbin;
2417 LOGD("type(%d) path is creating", type);
2419 case MM_PLAYER_STREAM_TYPE_AUDIO:
2421 if (mainbin[MMPLAYER_M_SRC].gst)
2422 src_id = MMPLAYER_M_2ND_SRC;
2424 src_id = MMPLAYER_M_SRC;
2425 queue_id = MMPLAYER_M_A_BUFFER;
2427 case MM_PLAYER_STREAM_TYPE_VIDEO:
2429 src_id = MMPLAYER_M_SRC;
2430 queue_id = MMPLAYER_M_V_BUFFER;
2432 case MM_PLAYER_STREAM_TYPE_TEXT:
2433 prefix = "subtitle";
2434 src_id = MMPLAYER_M_SUBSRC;
2435 queue_id = MMPLAYER_M_S_BUFFER;
2438 LOGE("invalid type %d", type);
2442 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2443 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2446 src = gst_element_factory_make("appsrc", src_name);
2448 LOGF("failed to create %s", src_name);
2452 mainbin[src_id].id = src_id;
2453 mainbin[src_id].gst = src;
2455 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2456 "caps", caps, NULL);
2458 /* size of many video frames are larger than default blocksize as 4096 */
2459 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2460 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2462 if (player->media_stream_buffer_max_size[type] > 0)
2463 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2465 if (player->media_stream_buffer_min_percent[type] > 0)
2466 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2468 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2469 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2471 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2472 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2473 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2474 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2475 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2476 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2479 queue = gst_element_factory_make("queue2", queue_name);
2481 LOGE("failed to create %s", queue_name);
2484 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2486 mainbin[queue_id].id = queue_id;
2487 mainbin[queue_id].gst = queue;
2489 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2490 LOGE("failed to add src");
2494 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2495 LOGE("failed to add queue");
2499 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2500 LOGE("failed to link src and queue");
2504 /* create decoder */
2505 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2507 LOGE("failed to get srcpad of queue");
2511 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2512 _mmplayer_gst_create_decoder(player, srcpad, caps);
2514 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2515 LOGE("failed to create decoder");
2516 gst_object_unref(GST_OBJECT(srcpad));
2520 gst_object_unref(GST_OBJECT(srcpad));
2524 if (mainbin[src_id].gst) {
2525 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2526 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2527 gst_object_unref(mainbin[src_id].gst);
2528 mainbin[src_id].gst = NULL;
2531 if (mainbin[queue_id].gst) {
2532 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2533 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2534 gst_object_unref(mainbin[queue_id].gst);
2535 mainbin[queue_id].gst = NULL;
2542 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2544 GstPad *sinkpad = NULL;
2545 GstCaps *caps = NULL;
2546 GstElement *new_element = NULL;
2547 GstStructure *str = NULL;
2548 const gchar *name = NULL;
2550 mmplayer_t *player = (mmplayer_t *)data;
2554 MMPLAYER_RETURN_IF_FAIL(element && pad);
2555 MMPLAYER_RETURN_IF_FAIL(player &&
2557 player->pipeline->mainbin);
2559 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2560 * num_dynamic_pad will decreased after creating a sinkbin.
2562 player->num_dynamic_pad++;
2563 LOGD("stream count inc : %d", player->num_dynamic_pad);
2565 caps = gst_pad_query_caps(pad, NULL);
2566 MMPLAYER_CHECK_NULL(caps);
2568 str = gst_caps_get_structure(caps, 0);
2569 name = gst_structure_get_string(str, "media");
2571 LOGE("cannot get mimetype from structure.");
2575 if (strstr(name, "video")) {
2577 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2579 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2580 if (player->v_stream_caps) {
2581 gst_caps_unref(player->v_stream_caps);
2582 player->v_stream_caps = NULL;
2585 new_element = gst_element_factory_make("fakesink", NULL);
2586 player->num_dynamic_pad--;
2591 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2592 LOGE("failed to autoplug for caps");
2596 gst_caps_unref(caps);
2601 /* excute new_element if created*/
2603 LOGD("adding new element to pipeline");
2605 /* set state to READY before add to bin */
2606 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2608 /* add new element to the pipeline */
2609 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2610 LOGE("failed to add autoplug element to bin");
2614 /* get pad from element */
2615 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2617 LOGE("failed to get sinkpad from autoplug element");
2622 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2623 LOGE("failed to link autoplug element");
2627 gst_object_unref(sinkpad);
2630 /* run. setting PLAYING here since streamming source is live source */
2631 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2635 gst_caps_unref(caps);
2641 STATE_CHANGE_FAILED:
2643 /* FIXIT : take care if new_element has already added to pipeline */
2645 gst_object_unref(GST_OBJECT(new_element));
2648 gst_object_unref(GST_OBJECT(sinkpad));
2651 gst_caps_unref(caps);
2653 /* FIXIT : how to inform this error to MSL ????? */
2654 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2655 * then post an error to application
2660 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2662 mmplayer_t *player = (mmplayer_t *)data;
2666 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2667 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2668 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2669 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2671 * [1] audio and video will be dumped with filesink.
2672 * [2] autoplugging is done by just using pad caps.
2673 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2674 * and the video will be dumped via filesink.
2676 if (player->num_dynamic_pad == 0) {
2677 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2679 if (!_mmplayer_gst_remove_fakesink(player,
2680 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2681 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2682 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2683 * source element are not same. To overcome this situation, this function will called
2684 * several places and several times. Therefore, this is not an error case.
2689 /* create dot before error-return. for debugging */
2690 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2692 player->no_more_pad = TRUE;
2698 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2700 GstElement *element = NULL;
2701 gchar *user_agent = NULL;
2702 MMHandleType attrs = 0;
2705 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2707 /* get profile attribute */
2708 attrs = MMPLAYER_GET_ATTRS(player);
2710 LOGE("failed to get content attribute");
2714 element = gst_element_factory_make("rtspsrc", "rtsp source");
2716 LOGE("failed to create rtspsrc element");
2721 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2723 SECURE_LOGD("user_agent : %s", user_agent);
2725 /* setting property to streaming source */
2726 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2728 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2730 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2731 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2732 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2733 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2740 __mmplayer_gst_make_http_src(mmplayer_t *player)
2742 #define MAX_RETRY_COUNT 10
2743 GstElement *element = NULL;
2744 MMHandleType attrs = 0;
2745 gchar *user_agent, *cookies, **cookie_list;
2746 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2747 user_agent = cookies = NULL;
2751 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2753 /* get profile attribute */
2754 attrs = MMPLAYER_GET_ATTRS(player);
2756 LOGE("failed to get content attribute");
2760 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2762 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2764 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2769 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2770 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2772 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2773 http_timeout = player->ini.http_timeout;
2776 SECURE_LOGD("location : %s", player->profile.uri);
2777 SECURE_LOGD("cookies : %s", cookies);
2778 SECURE_LOGD("user_agent : %s", user_agent);
2779 LOGD("timeout : %d", http_timeout);
2781 /* setting property to streaming source */
2782 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2783 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2784 "retries", MAX_RETRY_COUNT, NULL);
2786 /* parsing cookies */
2787 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2788 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2789 g_strfreev(cookie_list);
2793 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2795 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2796 LOGW("[DASH] this is still experimental feature");
2803 __mmplayer_gst_make_file_src(mmplayer_t *player)
2805 GstElement *element = NULL;
2808 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2810 LOGD("using filesrc for 'file://' handler");
2811 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2812 LOGE("failed to get storage info");
2816 element = gst_element_factory_make("filesrc", "source");
2818 LOGE("failed to create filesrc");
2822 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2829 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2831 mmplayer_t *player = (mmplayer_t *)data;
2833 g_return_val_if_fail(player, FALSE);
2834 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2836 gst_message_ref(msg);
2838 g_mutex_lock(&player->bus_msg_q_lock);
2839 g_queue_push_tail(player->bus_msg_q, msg);
2840 g_mutex_unlock(&player->bus_msg_q_lock);
2842 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2843 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2844 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2848 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2850 mmplayer_t *player = (mmplayer_t *)(data);
2851 GstMessage *msg = NULL;
2855 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2857 player->pipeline->mainbin &&
2858 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2861 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2863 LOGE("cannot get BUS from the pipeline");
2867 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2869 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2870 while (!player->bus_msg_thread_exit) {
2871 g_mutex_lock(&player->bus_msg_q_lock);
2872 msg = g_queue_pop_head(player->bus_msg_q);
2873 g_mutex_unlock(&player->bus_msg_q_lock);
2875 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2878 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2879 /* handle the gst msg */
2880 __mmplayer_gst_bus_msg_callback(msg, player);
2881 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2882 gst_message_unref(msg);
2885 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2886 gst_object_unref(GST_OBJECT(bus));
2893 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
2895 gint64 dur_nsec = 0;
2898 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2900 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2901 return MM_ERROR_NONE;
2903 /* NOTE : duration cannot be zero except live streaming.
2904 * Since some element could have some timing problemn with quering duration, try again.
2906 if (player->duration == 0) {
2907 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2908 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2909 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2910 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2911 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2912 player->pending_seek.is_pending = true;
2913 player->pending_seek.pos = position;
2914 player->seek_state = MMPLAYER_SEEK_NONE;
2915 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2916 return MM_ERROR_PLAYER_NO_OP;
2918 player->seek_state = MMPLAYER_SEEK_NONE;
2919 return MM_ERROR_PLAYER_SEEK;
2922 player->duration = dur_nsec;
2925 if (player->duration > 0 && player->duration < position) {
2926 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2927 return MM_ERROR_INVALID_ARGUMENT;
2931 return MM_ERROR_NONE;
2935 __mmplayer_gst_check_seekable(mmplayer_t *player)
2937 GstQuery *query = NULL;
2938 gboolean seekable = FALSE;
2940 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2944 query = gst_query_new_seeking(GST_FORMAT_TIME);
2945 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2946 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2947 gst_query_unref(query);
2950 LOGW("non-seekable content");
2951 player->seek_state = MMPLAYER_SEEK_NONE;
2955 LOGW("failed to get seeking query");
2956 gst_query_unref(query); /* keep seeking operation */
2963 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
2965 GstState element_state = GST_STATE_VOID_PENDING;
2966 GstState element_pending_state = GST_STATE_VOID_PENDING;
2967 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2971 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2972 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2974 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2977 ret = gst_element_set_state(element, state);
2978 if (ret == GST_STATE_CHANGE_FAILURE) {
2979 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2981 /* dump state of all element */
2982 _mmplayer_dump_pipeline_state(player);
2984 return MM_ERROR_PLAYER_INTERNAL;
2987 /* return here so state transition to be done in async mode */
2989 LOGD("async state transition. not waiting for state complete.");
2990 return MM_ERROR_NONE;
2993 /* wait for state transition */
2994 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2995 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2996 LOGE("failed to change [%s] element state to [%s] within %d sec",
2997 GST_ELEMENT_NAME(element),
2998 gst_element_state_get_name(state), timeout);
3000 LOGE(" [%s] state : %s pending : %s",
3001 GST_ELEMENT_NAME(element),
3002 gst_element_state_get_name(element_state),
3003 gst_element_state_get_name(element_pending_state));
3005 /* dump state of all element */
3006 _mmplayer_dump_pipeline_state(player);
3008 return MM_ERROR_PLAYER_INTERNAL;
3011 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3015 return MM_ERROR_NONE;
3019 _mmplayer_gst_start(mmplayer_t *player)
3021 int ret = MM_ERROR_NONE;
3022 gboolean async = FALSE;
3026 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3028 /* NOTE : if SetPosition was called before Start. do it now
3029 * streaming doesn't support it. so it should be always sync
3030 * !!create one more api to check if there is pending seek rather than checking variables
3032 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3033 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3034 ret = _mmplayer_gst_pause(player, FALSE);
3035 if (ret != MM_ERROR_NONE) {
3036 LOGE("failed to set state to PAUSED for pending seek");
3040 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3041 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3042 LOGW("failed to seek pending postion. starting from the begin of content");
3045 LOGD("current state before doing transition");
3046 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3047 MMPLAYER_PRINT_STATE(player);
3049 /* set pipeline state to PLAYING */
3050 ret = _mmplayer_gst_set_state(player,
3051 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3052 if (ret != MM_ERROR_NONE) {
3053 LOGE("failed to set state to PLAYING");
3057 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3059 /* generating debug info before returning error */
3060 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3068 _mmplayer_gst_stop(mmplayer_t *player)
3070 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3071 MMHandleType attrs = 0;
3072 gboolean rewind = FALSE;
3074 int ret = MM_ERROR_NONE;
3078 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3079 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3081 LOGD("current state before doing transition");
3082 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3083 MMPLAYER_PRINT_STATE(player);
3085 attrs = MMPLAYER_GET_ATTRS(player);
3087 LOGE("cannot get content attribute");
3088 return MM_ERROR_PLAYER_INTERNAL;
3091 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3092 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3094 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3095 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3098 if (player->es_player_push_mode)
3099 /* disable the async state transition because there could be no data in the pipeline */
3100 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3103 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3105 if (player->es_player_push_mode) {
3106 /* enable the async state transition as default operation */
3107 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3110 /* return if set_state has failed */
3111 if (ret != MM_ERROR_NONE) {
3112 LOGE("failed to set state.");
3118 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3119 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3120 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3121 LOGW("failed to rewind");
3122 ret = MM_ERROR_PLAYER_SEEK;
3127 player->sent_bos = FALSE;
3129 if (player->es_player_push_mode) //for cloudgame
3132 /* wait for seek to complete */
3133 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3134 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3135 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3137 LOGE("fail to stop player.");
3138 ret = MM_ERROR_PLAYER_INTERNAL;
3139 _mmplayer_dump_pipeline_state(player);
3142 /* generate dot file if enabled */
3143 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3151 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3153 int ret = MM_ERROR_NONE;
3157 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3158 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3160 LOGD("current state before doing transition");
3161 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3162 MMPLAYER_PRINT_STATE(player);
3164 /* set pipeline status to PAUSED */
3165 ret = _mmplayer_gst_set_state(player,
3166 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3171 if (ret != MM_ERROR_NONE) {
3172 GstMessage *msg = NULL;
3173 GTimer *timer = NULL;
3174 gdouble MAX_TIMEOUT_SEC = 3;
3176 LOGE("failed to set state to PAUSED");
3178 if (!player->bus_watcher) {
3179 LOGE("there is no bus msg thread. pipeline is shutting down.");
3183 if (player->msg_posted) {
3184 LOGE("error msg is already posted.");
3188 timer = g_timer_new();
3189 g_timer_start(timer);
3191 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3194 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3196 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3197 GError *error = NULL;
3199 /* parse error code */
3200 gst_message_parse_error(msg, &error, NULL);
3202 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3203 /* Note : the streaming error from the streaming source is handled
3204 * using __mmplayer_handle_streaming_error.
3206 __mmplayer_handle_streaming_error(player, msg);
3209 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3211 if (error->domain == GST_STREAM_ERROR)
3212 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3213 else if (error->domain == GST_RESOURCE_ERROR)
3214 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3215 else if (error->domain == GST_LIBRARY_ERROR)
3216 ret = __mmplayer_gst_handle_library_error(player, error->code);
3217 else if (error->domain == GST_CORE_ERROR)
3218 ret = __mmplayer_gst_handle_core_error(player, error->code);
3220 g_error_free(error);
3222 player->msg_posted = TRUE;
3224 gst_message_unref(msg);
3226 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3228 gst_object_unref(bus);
3229 g_timer_stop(timer);
3230 g_timer_destroy(timer);
3235 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3236 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3237 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3239 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3242 /* generate dot file before returning error */
3243 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3251 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3253 int ret = MM_ERROR_NONE;
3258 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3259 MM_ERROR_PLAYER_NOT_INITIALIZED);
3261 LOGD("current state before doing transition");
3262 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3263 MMPLAYER_PRINT_STATE(player);
3266 LOGD("do async state transition to PLAYING");
3268 /* set pipeline state to PLAYING */
3269 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3271 ret = _mmplayer_gst_set_state(player,
3272 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3273 if (ret != MM_ERROR_NONE) {
3274 LOGE("failed to set state to PLAYING");
3279 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3282 /* generate dot file */
3283 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3290 /* sending event to one of sinkelements */
3292 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3294 GstEvent *event2 = NULL;
3295 GList *sinks = NULL;
3296 gboolean res = FALSE;
3299 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3300 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3302 /* While adding subtitles in live feeds seek is getting called.
3303 Adding defensive check in framework layer.*/
3304 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3305 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3306 LOGE("Should not send seek event during live playback");
3311 if (player->play_subtitle)
3312 event2 = gst_event_copy((const GstEvent *)event);
3314 sinks = player->sink_elements;
3316 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3318 if (GST_IS_ELEMENT(sink)) {
3319 /* keep ref to the event */
3320 gst_event_ref(event);
3322 if ((res = gst_element_send_event(sink, event))) {
3323 LOGD("sending event[%s] to sink element [%s] success!",
3324 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3326 /* rtsp case, asyn_done is not called after seek during pause state */
3327 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3328 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3329 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3330 LOGD("RTSP seek completed, after pause state..");
3331 player->seek_state = MMPLAYER_SEEK_NONE;
3332 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3338 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3339 sinks = g_list_next(sinks);
3346 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3347 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3350 sinks = g_list_next(sinks);
3353 /* Note : Textbin is not linked to the video or audio bin.
3354 * It needs to send the event to the text sink seperatelly.
3356 if (player->play_subtitle && player->pipeline) {
3357 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3359 if (GST_IS_ELEMENT(text_sink)) {
3360 /* keep ref to the event */
3361 gst_event_ref(event2);
3363 if ((res = gst_element_send_event(text_sink, event2)))
3364 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3365 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3367 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3368 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3370 gst_event_unref(event2);
3374 gst_event_unref(event);
3382 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3383 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3384 gint64 cur, GstSeekType stop_type, gint64 stop)
3386 GstEvent *event = NULL;
3387 gboolean result = FALSE;
3391 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3393 if (player->pipeline && player->pipeline->textbin)
3394 __mmplayer_drop_subtitle(player, FALSE);
3396 event = gst_event_new_seek(rate, format, flags, cur_type,
3397 cur, stop_type, stop);
3399 result = _mmplayer_gst_send_event_to_sink(player, event);
3407 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3409 int ret = MM_ERROR_NONE;
3410 gint64 pos_nsec = 0;
3411 gboolean accurated = FALSE;
3412 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3415 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3416 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3418 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3419 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3422 ret = __mmplayer_gst_check_duration(player, position);
3423 if (ret != MM_ERROR_NONE) {
3424 LOGE("failed to check duration 0x%X", ret);
3425 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3428 if (!__mmplayer_gst_check_seekable(player))
3429 return MM_ERROR_PLAYER_NO_OP;
3431 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3432 position, player->playback_rate, player->duration);
3434 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3435 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3436 This causes problem is position calculation during normal pause resume scenarios also.
3437 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3438 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3439 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3440 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3441 LOGW("getting current position failed in seek");
3443 player->last_position = pos_nsec;
3444 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3447 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3448 LOGD("not completed seek");
3449 return MM_ERROR_PLAYER_DOING_SEEK;
3452 if (!internal_called)
3453 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3455 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3456 that's why set position through property. */
3457 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3458 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3459 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3460 (!player->videodec_linked) && (!player->audiodec_linked)) {
3462 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3463 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3465 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3466 player->seek_state = MMPLAYER_SEEK_NONE;
3467 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3469 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3471 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3473 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3475 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3476 GST_FORMAT_TIME, seek_flags,
3477 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3478 LOGE("failed to set position");
3483 /* NOTE : store last seeking point to overcome some bad operation
3484 * (returning zero when getting current position) of some elements
3486 player->last_position = position;
3488 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3489 if (player->playback_rate > 1.0)
3490 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3492 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3493 LOGD("buffering should be reset after seeking");
3494 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3495 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3499 return MM_ERROR_NONE;
3502 player->pending_seek.is_pending = true;
3503 player->pending_seek.pos = position;
3505 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3506 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3507 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3508 player->pending_seek.pos);
3510 return MM_ERROR_NONE;
3513 player->seek_state = MMPLAYER_SEEK_NONE;
3514 return MM_ERROR_PLAYER_SEEK;
3518 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3520 #define TRICKPLAY_OFFSET GST_MSECOND
3522 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3523 gint64 pos_nsec = 0;
3524 gboolean ret = TRUE;
3526 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3527 MM_ERROR_PLAYER_NOT_INITIALIZED);
3529 current_state = MMPLAYER_CURRENT_STATE(player);
3531 /* NOTE : query position except paused state to overcome some bad operation
3532 * please refer to below comments in details
3534 if (current_state != MM_PLAYER_STATE_PAUSED)
3535 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3537 /* NOTE : get last point to overcome some bad operation of some elements
3538 *(returning zero when getting current position in paused state
3539 * and when failed to get postion during seeking
3541 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3542 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3544 if (player->playback_rate < 0.0)
3545 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3547 pos_nsec = player->last_position;
3550 pos_nsec = player->last_position;
3552 player->last_position = pos_nsec;
3554 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3557 if (player->duration > 0 && pos_nsec > player->duration)
3558 pos_nsec = player->duration;
3560 player->last_position = pos_nsec;
3563 *position = pos_nsec;
3565 return MM_ERROR_NONE;
3569 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3571 #define STREAMING_IS_FINISHED 0
3572 #define BUFFERING_MAX_PER 100
3573 #define DEFAULT_PER_VALUE -1
3574 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3576 mmplayer_gst_element_t *mainbin = NULL;
3577 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3578 gint64 buffered_total = 0;
3579 gint64 position = 0;
3580 gint buffered_sec = -1;
3581 GstBufferingMode mode = GST_BUFFERING_STREAM;
3582 gint64 content_size_time = player->duration;
3583 guint64 content_size_bytes = player->http_content_size;
3585 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3587 player->pipeline->mainbin,
3588 MM_ERROR_PLAYER_NOT_INITIALIZED);
3590 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3595 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3596 /* and rtsp is not ready yet. */
3597 LOGW("it's only used for http streaming case");
3598 return MM_ERROR_PLAYER_NO_OP;
3601 if (content_size_time <= 0 || content_size_bytes <= 0) {
3602 LOGW("there is no content size");
3603 return MM_ERROR_NONE;
3606 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3607 LOGW("fail to get current position");
3608 return MM_ERROR_NONE;
3611 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3612 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3614 mainbin = player->pipeline->mainbin;
3615 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3617 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3618 GstQuery *query = NULL;
3619 gint byte_in_rate = 0, byte_out_rate = 0;
3620 gint64 estimated_total = 0;
3622 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3623 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3624 LOGW("fail to get buffering query from queue2");
3626 gst_query_unref(query);
3627 return MM_ERROR_NONE;
3630 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3631 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3633 if (mode == GST_BUFFERING_STREAM) {
3634 /* using only queue in case of push mode(ts / mp3) */
3635 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3636 GST_FORMAT_BYTES, &buffered_total)) {
3637 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3638 end_per = 100 * buffered_total / content_size_bytes;
3641 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3643 guint num_of_ranges = 0;
3644 gint64 start_byte = 0, stop_byte = 0;
3646 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3647 if (estimated_total != STREAMING_IS_FINISHED) {
3648 /* buffered size info from queue2 */
3649 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3650 for (idx = 0; idx < num_of_ranges; idx++) {
3651 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3652 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3654 buffered_total += (stop_byte - start_byte);
3657 end_per = BUFFERING_MAX_PER;
3660 gst_query_unref(query);
3663 if (end_per == DEFAULT_PER_VALUE) {
3664 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3666 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3668 /* buffered size info from multiqueue */
3669 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3670 guint curr_size_bytes = 0;
3671 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3672 "curr-size-bytes", &curr_size_bytes, NULL);
3673 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3674 buffered_total += curr_size_bytes;
3677 if (avg_byterate > 0)
3678 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3679 else if (player->total_maximum_bitrate > 0)
3680 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3681 else if (player->total_bitrate > 0)
3682 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3684 if (buffered_sec >= 0)
3685 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3689 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3690 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3692 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3693 buffered_total, buffered_sec, *start_pos, *end_pos);
3695 return MM_ERROR_NONE;
3699 _mmplayer_gst_create_source(mmplayer_t *player)
3701 GstElement *element = NULL;
3704 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3705 player->pipeline->mainbin, NULL);
3707 /* setup source for gapless play */
3708 switch (player->profile.uri_type) {
3710 case MM_PLAYER_URI_TYPE_FILE:
3711 element = __mmplayer_gst_make_file_src(player);
3713 case MM_PLAYER_URI_TYPE_URL_HTTP:
3714 element = __mmplayer_gst_make_http_src(player);
3717 LOGE("not support uri type %d", player->profile.uri_type);
3722 LOGE("failed to create source element");
3731 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3733 MMHandleType attrs = 0;
3736 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3737 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3739 /* get profile attribute */
3740 attrs = MMPLAYER_GET_ATTRS(player);
3742 LOGE("failed to get content attribute");
3743 return MM_ERROR_PLAYER_INTERNAL;
3746 SECURE_LOGD("uri : %s", player->profile.uri);
3748 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3749 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3750 LOGE("failed to commit");
3752 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3753 return MM_ERROR_PLAYER_INTERNAL;
3755 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3756 return MM_ERROR_PLAYER_INTERNAL;
3758 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3759 return MM_ERROR_PLAYER_INTERNAL;
3762 return MM_ERROR_NONE;
3766 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3768 mmplayer_gst_element_t *mainbin = NULL;
3769 GstElement *src_elem = NULL;
3770 GstElement *autoplug_elem = NULL;
3771 GList *element_bucket = NULL;
3772 MMHandleType attrs = 0;
3773 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3776 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3777 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3779 /* get profile attribute */
3780 attrs = MMPLAYER_GET_ATTRS(player);
3782 LOGE("failed to get content attribute");
3783 return MM_ERROR_PLAYER_INTERNAL;
3786 LOGD("uri type %d", player->profile.uri_type);
3788 /* create source element */
3789 switch (player->profile.uri_type) {
3790 case MM_PLAYER_URI_TYPE_URL_RTSP:
3791 src_elem = __mmplayer_gst_make_rtsp_src(player);
3793 case MM_PLAYER_URI_TYPE_URL_HTTP:
3794 src_elem = __mmplayer_gst_make_http_src(player);
3796 case MM_PLAYER_URI_TYPE_FILE:
3797 src_elem = __mmplayer_gst_make_file_src(player);
3799 case MM_PLAYER_URI_TYPE_SS:
3801 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3802 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3804 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3808 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3809 LOGD("get timeout from ini");
3810 http_timeout = player->ini.http_timeout;
3813 /* setting property to streaming source */
3814 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3817 case MM_PLAYER_URI_TYPE_MEM:
3819 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3821 src_elem = gst_element_factory_make("appsrc", "mem-source");
3823 LOGE("failed to create appsrc element");
3827 g_object_set(src_elem, "stream-type", stream_type,
3828 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3830 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3831 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3832 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3833 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3837 LOGE("not support uri type");
3842 LOGE("failed to create source element");
3843 return MM_ERROR_PLAYER_INTERNAL;
3846 mainbin = player->pipeline->mainbin;
3848 /* take source element */
3849 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3851 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3852 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3853 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3855 /* create next element for auto-plugging */
3856 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3857 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3858 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3859 if (!autoplug_elem) {
3860 LOGE("failed to create typefind element");
3864 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3865 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3866 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3867 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3868 autoplug_elem = _mmplayer_gst_make_decodebin(player);
3869 if (!autoplug_elem) {
3870 LOGE("failed to create decodebin");
3874 /* default size of mq in decodebin is 2M
3875 * but it can cause blocking issue during seeking depends on content. */
3876 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3879 if (autoplug_elem) {
3880 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3881 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3882 mainbin[autoplug_elem_id].gst = autoplug_elem;
3884 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3887 /* add elements to pipeline */
3888 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3889 LOGE("failed to add elements to pipeline");
3893 /* linking elements in the bucket by added order. */
3894 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3895 LOGE("failed to link some elements");
3899 /* FIXME: need to check whether this is required or not. */
3900 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3901 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3902 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3903 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3905 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3906 LOGE("failed to create fakesink");
3909 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3911 /* take ownership of fakesink. we are reusing it */
3912 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3914 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3915 LOGE("failed to add fakesink to bin");
3916 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3921 g_list_free(element_bucket);
3924 return MM_ERROR_NONE;
3927 g_list_free(element_bucket);
3929 if (mainbin[MMPLAYER_M_SRC].gst)
3930 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3932 if (mainbin[autoplug_elem_id].gst)
3933 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3935 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3936 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3938 mainbin[MMPLAYER_M_SRC].gst = NULL;
3939 mainbin[autoplug_elem_id].gst = NULL;
3940 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3942 return MM_ERROR_PLAYER_INTERNAL;
3946 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
3949 mmplayer_gst_element_t *mainbin = NULL;
3952 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3953 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3955 mainbin = player->pipeline->mainbin;
3957 /* connect bus callback */
3958 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3960 LOGE("cannot get bus from pipeline");
3961 return MM_ERROR_PLAYER_INTERNAL;
3964 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3965 player->context.thread_default = g_main_context_get_thread_default();
3966 if (player->context.thread_default == NULL) {
3967 player->context.thread_default = g_main_context_default();
3968 LOGD("thread-default context is the global default context");
3970 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3972 /* set sync handler to get tag synchronously */
3973 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3974 gst_object_unref(GST_OBJECT(bus));
3976 /* create gst bus_msb_cb thread */
3977 g_mutex_init(&player->bus_msg_thread_mutex);
3978 g_cond_init(&player->bus_msg_thread_cond);
3979 player->bus_msg_thread_exit = FALSE;
3980 player->bus_msg_thread =
3981 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3982 if (!player->bus_msg_thread) {
3983 LOGE("failed to create gst BUS msg thread");
3984 g_mutex_clear(&player->bus_msg_thread_mutex);
3985 g_cond_clear(&player->bus_msg_thread_cond);
3986 return MM_ERROR_PLAYER_INTERNAL;
3990 return MM_ERROR_NONE;
3994 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
3996 mmplayer_gst_element_t *mainbin = NULL;
3997 MMMessageParamType msg_param = {0,};
3998 GstElement *element = NULL;
3999 MMHandleType attrs = 0;
4001 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4005 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4006 LOGE("player is not initialized");
4010 mainbin = player->pipeline->mainbin;
4011 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4013 attrs = MMPLAYER_GET_ATTRS(player);
4015 LOGE("fail to get attributes");
4019 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4021 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4022 LOGE("failed to parse profile");
4023 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4027 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4028 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4029 LOGE("dash or hls is not supportable");
4030 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4034 element = _mmplayer_gst_create_source(player);
4036 LOGE("no source element was created");
4040 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4041 LOGE("failed to add source element to pipeline");
4042 gst_object_unref(GST_OBJECT(element));
4047 /* take source element */
4048 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4049 mainbin[MMPLAYER_M_SRC].gst = element;
4053 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4054 if (player->streamer == NULL) {
4055 player->streamer = _mm_player_streaming_create();
4056 _mm_player_streaming_initialize(player->streamer, TRUE);
4059 elem_idx = MMPLAYER_M_TYPEFIND;
4060 element = gst_element_factory_make("typefind", "typefinder");
4061 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4062 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4064 elem_idx = MMPLAYER_M_AUTOPLUG;
4065 element = _mmplayer_gst_make_decodebin(player);
4068 /* check autoplug element is OK */
4070 LOGE("can not create element(%d)", elem_idx);
4074 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4075 LOGE("failed to add sinkbin to pipeline");
4076 gst_object_unref(GST_OBJECT(element));
4081 mainbin[elem_idx].id = elem_idx;
4082 mainbin[elem_idx].gst = element;
4084 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4085 LOGE("Failed to link src - autoplug(or typefind)");
4089 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4090 LOGE("Failed to change state of src element");
4094 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4095 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4096 LOGE("Failed to change state of decodebin");
4100 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4101 LOGE("Failed to change state of src element");
4106 player->gapless.stream_changed = TRUE;
4107 player->gapless.running = TRUE;
4113 MMPLAYER_PLAYBACK_UNLOCK(player);
4115 if (!player->msg_posted) {
4116 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4117 player->msg_posted = TRUE;