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 : [0x%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, player, 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_player_set_attribute((MMHandleType)player, NULL,\
759 playertag, new_string, strlen(new_string), NULL); \
760 MMPLAYER_FREEIF(new_string); \
762 mm_player_set_attribute((MMHandleType)player, NULL,\
763 playertag, string, strlen(string), NULL); \
765 MMPLAYER_FREEIF(string); \
770 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
772 GstSample *sample = NULL;\
773 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
774 GstMapInfo info = GST_MAP_INFO_INIT;\
775 buffer = gst_sample_get_buffer(sample);\
776 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
777 LOGD("failed to get image data from tag");\
778 gst_sample_unref(sample);\
781 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
782 MMPLAYER_FREEIF(player->album_art);\
783 player->album_art = (gchar *)g_malloc(info.size);\
784 if (player->album_art) {\
785 memcpy(player->album_art, info.data, info.size);\
786 mm_player_set_attribute((MMHandleType)player, NULL,\
787 playertag, (void *)player->album_art, info.size, NULL); \
788 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
789 msg_param.data = (void *)player->album_art;\
790 msg_param.size = info.size;\
791 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
792 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
795 gst_buffer_unmap(buffer, &info);\
796 gst_sample_unref(sample);\
800 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
802 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
805 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
806 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
807 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
808 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
809 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
811 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
812 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
813 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
814 mm_player_set_attribute((MMHandleType)player, NULL,\
815 "content_audio_bitrate", v_uint, NULL); \
816 player->bitrate[track_type] = v_uint; \
817 player->total_bitrate = 0; \
818 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
819 player->total_bitrate += player->bitrate[i]; \
820 mm_player_set_attribute((MMHandleType)player, NULL,\
821 playertag, player->total_bitrate, NULL); \
822 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
823 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
824 player->maximum_bitrate[track_type] = v_uint; \
825 player->total_maximum_bitrate = 0; \
826 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
827 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
828 mm_player_set_attribute((MMHandleType)player, NULL,\
829 playertag, player->total_maximum_bitrate, NULL); \
830 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
832 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
839 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
841 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
843 string = g_strdup_printf("%d", g_date_get_year(date));\
844 mm_player_set_attribute((MMHandleType)player, NULL,\
845 playertag, string, strlen(string), NULL); \
846 SECURE_LOGD("metainfo year : %s", string);\
847 MMPLAYER_FREEIF(string);\
853 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
856 if (datetime != NULL) {\
857 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
858 mm_player_set_attribute((MMHandleType)player, NULL,\
859 playertag, string, strlen(string), NULL); \
860 SECURE_LOGD("metainfo year : %s", string);\
861 MMPLAYER_FREEIF(string);\
862 gst_date_time_unref(datetime);\
868 GstTagList *tag_list = NULL;
873 GstDateTime *datetime = NULL;
875 GstBuffer *buffer = NULL;
877 MMMessageParamType msg_param = {0, };
879 /* currently not used. but those are needed for above macro */
880 //guint64 v_uint64 = 0;
881 //gdouble v_double = 0;
883 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
885 /* get tag list from gst message */
886 gst_message_parse_tag(msg, &tag_list);
888 /* store tags to player attributes */
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
890 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
891 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
892 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
893 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
894 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
896 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
899 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
901 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
902 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
903 MMPLAYER_UPDATE_TAG_LOCK(player);
904 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
905 MMPLAYER_UPDATE_TAG_UNLOCK(player);
906 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
908 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
909 if (player->video360_metadata.is_spherical == -1) {
910 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
911 mm_player_set_attribute((MMHandleType)player, NULL,
912 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
913 if (player->video360_metadata.is_spherical == 1) {
914 LOGD("This is spherical content for 360 playback.");
915 player->is_content_spherical = TRUE;
917 LOGD("This is not spherical content");
918 player->is_content_spherical = FALSE;
921 if (player->video360_metadata.projection_type_string) {
922 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
923 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
925 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
926 player->is_content_spherical = player->is_video360_enabled = FALSE;
930 if (player->video360_metadata.stereo_mode_string) {
931 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
932 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
933 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
934 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
935 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
936 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
938 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
939 player->is_content_spherical = player->is_video360_enabled = FALSE;
945 gst_tag_list_unref(tag_list);
950 /* if retval is FALSE, it will be dropped for perfomance. */
952 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
954 gboolean retval = FALSE;
956 if (!(player->pipeline && player->pipeline->mainbin)) {
957 LOGE("player pipeline handle is null");
961 switch (GST_MESSAGE_TYPE(message)) {
962 case GST_MESSAGE_TAG:
963 case GST_MESSAGE_EOS:
964 case GST_MESSAGE_ERROR:
965 case GST_MESSAGE_WARNING:
966 case GST_MESSAGE_CLOCK_LOST:
967 case GST_MESSAGE_NEW_CLOCK:
968 case GST_MESSAGE_ELEMENT:
969 case GST_MESSAGE_DURATION_CHANGED:
970 case GST_MESSAGE_ASYNC_START:
971 case GST_MESSAGE_STREAM_COLLECTION:
974 case GST_MESSAGE_ASYNC_DONE:
975 case GST_MESSAGE_STATE_CHANGED:
976 /* we only handle messages from pipeline */
977 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
982 case GST_MESSAGE_BUFFERING:
984 gint buffer_percent = 0;
987 gst_message_parse_buffering(message, &buffer_percent);
988 if (buffer_percent != MAX_BUFFER_PERCENT) {
989 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
993 if (!MMPLAYER_CMD_TRYLOCK(player)) {
994 LOGW("can't get cmd lock, send msg to bus");
998 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
999 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1000 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1003 MMPLAYER_CMD_UNLOCK(player);
1007 case GST_MESSAGE_STREAMS_SELECTED:
1009 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1010 break; /* drop msg */
1012 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1013 player->no_more_pad = TRUE;
1014 _mmplayer_pipeline_complete(NULL, player);
1027 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1029 guint64 data_size = 0;
1030 gint64 pos_nsec = 0;
1032 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1034 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1036 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1037 data_size = player->http_content_size;
1040 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1041 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1047 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1049 int ret = MM_ERROR_NONE;
1050 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1051 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1052 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1053 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1055 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1056 LOGW("do nothing for buffering msg");
1057 ret = MM_ERROR_PLAYER_INVALID_STATE;
1061 prev_state = MMPLAYER_PREV_STATE(player);
1062 current_state = MMPLAYER_CURRENT_STATE(player);
1063 target_state = MMPLAYER_TARGET_STATE(player);
1064 pending_state = MMPLAYER_PENDING_STATE(player);
1066 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1067 MMPLAYER_STATE_GET_NAME(prev_state),
1068 MMPLAYER_STATE_GET_NAME(current_state),
1069 MMPLAYER_STATE_GET_NAME(pending_state),
1070 MMPLAYER_STATE_GET_NAME(target_state),
1071 player->streamer->buffering_state);
1073 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1074 /* NOTE : if buffering has done, player has to go to target state. */
1075 switch (target_state) {
1076 case MM_PLAYER_STATE_PAUSED:
1078 switch (pending_state) {
1079 case MM_PLAYER_STATE_PLAYING:
1080 _mmplayer_gst_pause(player, TRUE);
1083 case MM_PLAYER_STATE_PAUSED:
1084 LOGD("player is already going to paused state, there is nothing to do.");
1087 case MM_PLAYER_STATE_NONE:
1088 case MM_PLAYER_STATE_NULL:
1089 case MM_PLAYER_STATE_READY:
1091 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1097 case MM_PLAYER_STATE_PLAYING:
1099 switch (pending_state) {
1100 case MM_PLAYER_STATE_NONE:
1102 if (current_state != MM_PLAYER_STATE_PLAYING)
1103 _mmplayer_gst_resume(player, TRUE);
1107 case MM_PLAYER_STATE_PAUSED:
1108 /* NOTE: It should be worked as asynchronously.
1109 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1111 if (current_state == MM_PLAYER_STATE_PLAYING) {
1112 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1113 * The current state should be changed to paused purposely to prevent state conflict.
1115 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1117 _mmplayer_gst_resume(player, TRUE);
1120 case MM_PLAYER_STATE_PLAYING:
1121 LOGD("player is already going to playing state, there is nothing to do.");
1124 case MM_PLAYER_STATE_NULL:
1125 case MM_PLAYER_STATE_READY:
1127 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1133 case MM_PLAYER_STATE_NULL:
1134 case MM_PLAYER_STATE_READY:
1135 case MM_PLAYER_STATE_NONE:
1137 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1141 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1142 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1144 switch (pending_state) {
1145 case MM_PLAYER_STATE_NONE:
1147 if (current_state != MM_PLAYER_STATE_PAUSED) {
1148 /* rtsp streaming pause makes rtsp server stop sending data. */
1149 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1150 LOGD("set pause state during buffering");
1151 _mmplayer_gst_pause(player, TRUE);
1157 case MM_PLAYER_STATE_PLAYING:
1158 /* rtsp streaming pause makes rtsp server stop sending data. */
1159 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1160 _mmplayer_gst_pause(player, TRUE);
1163 case MM_PLAYER_STATE_PAUSED:
1166 case MM_PLAYER_STATE_NULL:
1167 case MM_PLAYER_STATE_READY:
1169 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1178 static stream_variant_t *
1179 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1181 stream_variant_t *var_info = NULL;
1182 g_return_val_if_fail(self != NULL, NULL);
1184 var_info = g_new0(stream_variant_t, 1);
1185 if (!var_info) return NULL;
1186 var_info->bandwidth = self->bandwidth;
1187 var_info->width = self->width;
1188 var_info->height = self->height;
1193 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1199 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1200 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1202 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1203 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1204 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1206 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1207 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1208 player->http_content_size = (bytes > 0) ? bytes : 0;
1211 /* handling audio clip which has vbr. means duration is keep changing */
1212 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1221 __mmplayer_eos_timer_cb(gpointer u_data)
1223 mmplayer_t *player = NULL;
1224 MMHandleType attrs = 0;
1227 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1229 player = (mmplayer_t *)u_data;
1230 attrs = MMPLAYER_GET_ATTRS(player);
1232 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1236 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1237 if (ret_value != MM_ERROR_NONE)
1238 LOGE("seeking to 0 failed in repeat play");
1241 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1244 /* we are returning FALSE as we need only one posting */
1249 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1251 MMPLAYER_RETURN_IF_FAIL(player);
1253 /* post now if delay is zero */
1254 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1255 LOGD("eos delay is zero. posting EOS now");
1256 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1258 if (player->audio_decoded_cb)
1259 _mmplayer_cancel_eos_timer(player);
1264 /* cancel if existing */
1265 _mmplayer_cancel_eos_timer(player);
1267 /* init new timeout */
1268 /* NOTE : consider give high priority to this timer */
1269 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1271 player->eos_timer = g_timeout_add(delay_in_ms,
1272 __mmplayer_eos_timer_cb, player);
1274 player->context.global_default = g_main_context_default();
1275 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1277 /* check timer is valid. if not, send EOS now */
1278 if (player->eos_timer == 0) {
1279 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1280 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1285 __mmplayer_gst_pending_seek(mmplayer_t *player)
1287 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1288 int ret = MM_ERROR_NONE;
1292 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1294 if (!player->pending_seek.is_pending) {
1295 LOGD("pending seek is not reserved. nothing to do.");
1299 /* check player state if player could pending seek or not. */
1300 current_state = MMPLAYER_CURRENT_STATE(player);
1302 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1303 LOGW("try to pending seek in %s state, try next time. ",
1304 MMPLAYER_STATE_GET_NAME(current_state));
1308 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1310 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1311 if (ret != MM_ERROR_NONE)
1312 LOGE("failed to seek pending postion. just keep staying current position.");
1314 player->pending_seek.is_pending = false;
1322 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1324 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1326 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1328 audiobin = player->pipeline->audiobin; /* can be null */
1329 videobin = player->pipeline->videobin; /* can be null */
1330 textbin = player->pipeline->textbin; /* can be null */
1332 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1334 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1335 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1337 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1338 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1340 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1341 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1347 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1349 mmplayer_gst_element_t *textbin;
1352 MMPLAYER_RETURN_IF_FAIL(player &&
1354 player->pipeline->textbin);
1356 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1358 textbin = player->pipeline->textbin;
1361 LOGD("Drop subtitle text after getting EOS");
1363 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1364 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1366 player->is_subtitle_force_drop = TRUE;
1368 if (player->is_subtitle_force_drop == TRUE) {
1369 LOGD("Enable subtitle data path without drop");
1371 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1372 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1374 LOGD("non-connected with external display");
1376 player->is_subtitle_force_drop = FALSE;
1382 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1384 MMHandleType attrs = 0;
1389 /* NOTE : EOS event is comming multiple time. watch out it */
1390 /* check state. we only process EOS when pipeline state goes to PLAYING */
1391 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1392 LOGD("EOS received on non-playing state. ignoring it");
1396 if (player->pipeline && player->pipeline->textbin)
1397 __mmplayer_drop_subtitle(player, TRUE);
1399 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1400 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1402 /* rewind if repeat count is greater then zero */
1403 /* get play count */
1404 attrs = MMPLAYER_GET_ATTRS(player);
1406 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1408 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1410 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1411 if (player->playback_rate < 0.0) {
1412 player->resumed_by_rewind = TRUE;
1413 _mmplayer_set_mute((MMHandleType)player, false);
1414 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1417 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1420 player->sent_bos = FALSE;
1422 LOGD("do not post eos msg for repeating");
1427 if (player->pipeline)
1428 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1430 /* post eos message to application */
1431 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1433 /* reset last position */
1434 player->last_position = 0;
1441 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1443 GError *error = NULL;
1444 gchar *debug = NULL;
1448 /* generating debug info before returning error */
1449 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1451 /* get error code */
1452 gst_message_parse_error(msg, &error, &debug);
1454 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1455 /* Note : the streaming error from the streaming source is handled
1456 * using __mmplayer_handle_streaming_error.
1458 __mmplayer_handle_streaming_error(player, msg);
1460 /* dump state of all element */
1461 _mmplayer_dump_pipeline_state(player);
1463 /* traslate gst error code to msl error code. then post it
1464 * to application if needed
1466 __mmplayer_handle_gst_error(player, msg, error);
1469 LOGE("error debug : %s", debug);
1472 MMPLAYER_FREEIF(debug);
1473 g_error_free(error);
1480 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1482 MMMessageParamType msg_param = {0, };
1483 int bRet = MM_ERROR_NONE;
1486 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1488 if (!MMPLAYER_IS_STREAMING(player)) {
1489 LOGW("this is not streaming playback.");
1493 MMPLAYER_CMD_LOCK(player);
1495 if (!player->streamer) {
1496 LOGW("Pipeline is shutting down");
1497 MMPLAYER_CMD_UNLOCK(player);
1501 /* ignore the remained buffering message till getting 100% msg */
1502 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1503 gint buffer_percent = 0;
1505 gst_message_parse_buffering(msg, &buffer_percent);
1507 if (buffer_percent == MAX_BUFFER_PERCENT) {
1508 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1509 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1510 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1512 MMPLAYER_CMD_UNLOCK(player);
1516 /* ignore the remained buffering message */
1517 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1518 gint buffer_percent = 0;
1520 gst_message_parse_buffering(msg, &buffer_percent);
1522 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1523 player->streamer->buffering_percent, buffer_percent);
1525 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1526 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1527 player->streamer->buffering_req.is_pre_buffering = FALSE;
1529 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1531 LOGD("interrupted buffering - ignored the remained buffering msg!");
1532 MMPLAYER_CMD_UNLOCK(player);
1537 __mmplayer_update_buffer_setting(player, msg);
1539 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1541 if (bRet == MM_ERROR_NONE) {
1542 msg_param.connection.buffering = player->streamer->buffering_percent;
1543 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1545 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1546 player->pending_resume &&
1547 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1549 player->is_external_subtitle_added_now = FALSE;
1550 player->pending_resume = FALSE;
1551 _mmplayer_resume((MMHandleType)player);
1554 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1555 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1557 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1558 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1559 player->seek_state = MMPLAYER_SEEK_NONE;
1560 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1561 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1562 /* Considering the async state trasition in case of RTSP.
1563 After getting state change gst msg, seek cmpleted msg will be posted. */
1564 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1568 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1569 if (!player->streamer) {
1570 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1571 MMPLAYER_CMD_UNLOCK(player);
1575 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1577 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1578 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1580 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1581 msg_param.connection.buffering = player->streamer->buffering_percent;
1582 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1584 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1587 msg_param.connection.buffering = player->streamer->buffering_percent;
1588 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1591 MMPLAYER_CMD_UNLOCK(player);
1599 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1601 mmplayer_gst_element_t *mainbin;
1602 const GValue *voldstate, *vnewstate, *vpending;
1603 GstState oldstate = GST_STATE_NULL;
1604 GstState newstate = GST_STATE_NULL;
1605 GstState pending = GST_STATE_NULL;
1608 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1610 mainbin = player->pipeline->mainbin;
1612 /* we only handle messages from pipeline */
1613 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1616 /* get state info from msg */
1617 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1618 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1619 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1621 if (!voldstate || !vnewstate) {
1622 LOGE("received msg has wrong format.");
1626 oldstate = (GstState)voldstate->data[0].v_int;
1627 newstate = (GstState)vnewstate->data[0].v_int;
1629 pending = (GstState)vpending->data[0].v_int;
1631 LOGD("state changed [%s] : %s ---> %s final : %s",
1632 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1633 gst_element_state_get_name((GstState)oldstate),
1634 gst_element_state_get_name((GstState)newstate),
1635 gst_element_state_get_name((GstState)pending));
1637 if (newstate == GST_STATE_PLAYING) {
1638 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1640 int retVal = MM_ERROR_NONE;
1641 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1643 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1645 if (MM_ERROR_NONE != retVal)
1646 LOGE("failed to seek pending postion. just keep staying current position.");
1648 player->pending_seek.is_pending = false;
1652 if (oldstate == newstate) {
1653 LOGD("pipeline reports state transition to old state");
1658 case GST_STATE_PAUSED:
1660 gboolean prepare_async = FALSE;
1662 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1663 // managed prepare async case
1664 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1665 LOGD("checking prepare mode for async transition - %d", prepare_async);
1668 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1669 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1671 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1672 _mm_player_streaming_set_content_bitrate(player->streamer,
1673 player->total_maximum_bitrate, player->total_bitrate);
1675 if (player->pending_seek.is_pending) {
1676 LOGW("trying to do pending seek");
1677 MMPLAYER_CMD_LOCK(player);
1678 __mmplayer_gst_pending_seek(player);
1679 MMPLAYER_CMD_UNLOCK(player);
1685 case GST_STATE_PLAYING:
1687 if (MMPLAYER_IS_STREAMING(player)) {
1688 // managed prepare async case when buffering is completed
1689 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1690 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1691 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1692 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1694 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1696 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1697 if (player->streamer->buffering_percent < 100) {
1699 MMMessageParamType msg_param = {0, };
1700 LOGW("Posting Buffering Completed Message to Application !!!");
1702 msg_param.connection.buffering = 100;
1703 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1708 if (player->gapless.stream_changed) {
1709 _mmplayer_update_content_attrs(player, ATTR_ALL);
1710 player->gapless.stream_changed = FALSE;
1713 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1714 player->seek_state = MMPLAYER_SEEK_NONE;
1715 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1719 case GST_STATE_VOID_PENDING:
1720 case GST_STATE_NULL:
1721 case GST_STATE_READY:
1731 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1733 const gchar *structure_name;
1734 gint count = 0, idx = 0;
1737 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1739 if (gst_message_get_structure(msg) == NULL)
1742 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1743 if (!structure_name)
1746 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1748 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1749 const GValue *var_info = NULL;
1751 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1752 if (var_info != NULL) {
1753 if (player->adaptive_info.var_list)
1754 g_list_free_full(player->adaptive_info.var_list, g_free);
1756 /* share addr or copy the list */
1757 player->adaptive_info.var_list =
1758 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1760 count = g_list_length(player->adaptive_info.var_list);
1762 stream_variant_t *temp = NULL;
1764 /* print out for debug */
1765 LOGD("num of variant_info %d", count);
1766 for (idx = 0; idx < count; idx++) {
1767 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1769 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1775 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1776 gint num_buffers = 0;
1777 gint extra_num_buffers = 0;
1779 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1780 LOGD("video_num_buffers : %d", num_buffers);
1781 mm_player_set_attribute((MMHandleType)player, NULL,
1782 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1785 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1786 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1787 mm_player_set_attribute((MMHandleType)player, NULL,
1788 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1793 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1794 _mmplayer_track_update_text_attr_info(player, msg);
1796 /* custom message */
1797 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1798 MMMessageParamType msg_param = {0,};
1799 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1800 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1803 /* custom message for RTSP attribute :
1804 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1805 sdp which has contents info is received when rtsp connection is opened.
1806 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1807 if (!strcmp(structure_name, "rtspsrc_properties")) {
1808 gchar *audio_codec = NULL;
1809 gchar *video_codec = NULL;
1810 gchar *video_frame_size = NULL;
1812 gst_structure_get(gst_message_get_structure(msg),
1813 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1814 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1815 player->streaming_type = _mmplayer_get_stream_service_type(player);
1817 gst_structure_get(gst_message_get_structure(msg),
1818 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1819 LOGD("rtsp_audio_codec : %s", audio_codec);
1821 mm_player_set_attribute((MMHandleType)player, NULL,
1822 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1824 gst_structure_get(gst_message_get_structure(msg),
1825 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1826 LOGD("rtsp_video_codec : %s", video_codec);
1828 mm_player_set_attribute((MMHandleType)player, NULL,
1829 "content_video_codec", video_codec, strlen(video_codec), NULL);
1831 gst_structure_get(gst_message_get_structure(msg),
1832 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1833 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1834 if (video_frame_size) {
1835 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1836 mm_player_set_attribute((MMHandleType)player, NULL,
1837 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1838 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1840 g_strfreev(res_str);
1849 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1851 mmplayer_gst_element_t *mainbin;
1854 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1856 mainbin = player->pipeline->mainbin;
1858 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1860 /* we only handle messages from pipeline */
1861 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1864 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1865 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1866 player->seek_state = MMPLAYER_SEEK_NONE;
1867 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1868 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1869 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1870 LOGD("sync %s state(%s) with parent state(%s)",
1871 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1872 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1873 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1875 /* In case of streaming, pause is required before finishing seeking by buffering.
1876 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1877 Because the buffering state is controlled according to the state transition for force resume,
1878 the decodebin state should be paused as player state. */
1879 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1882 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1883 (player->streamer) &&
1884 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1885 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1886 GstQuery *query = NULL;
1887 gboolean busy = FALSE;
1890 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1891 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1892 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1893 gst_query_parse_buffering_percent(query, &busy, &percent);
1894 gst_query_unref(query);
1896 LOGD("buffered percent(%s): %d",
1897 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1901 __mmplayer_handle_buffering_playback(player);
1904 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1913 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1915 mmplayer_t *player = (mmplayer_t *)(data);
1917 MMPLAYER_RETURN_IF_FAIL(player);
1918 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1920 switch (GST_MESSAGE_TYPE(msg)) {
1921 case GST_MESSAGE_UNKNOWN:
1922 LOGD("unknown message received");
1925 case GST_MESSAGE_EOS:
1926 LOGD("GST_MESSAGE_EOS received");
1927 __mmplayer_gst_handle_eos_message(player, msg);
1930 case GST_MESSAGE_ERROR:
1931 _mmplayer_set_reconfigure_state(player, FALSE);
1932 __mmplayer_gst_handle_error_message(player, msg);
1935 case GST_MESSAGE_WARNING:
1938 GError *error = NULL;
1940 gst_message_parse_warning(msg, &error, &debug);
1942 LOGD("warning : %s", error->message);
1943 LOGD("debug : %s", debug);
1945 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1947 MMPLAYER_FREEIF(debug);
1948 g_error_free(error);
1952 case GST_MESSAGE_TAG:
1954 LOGD("GST_MESSAGE_TAG");
1955 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1956 LOGW("failed to extract tags from gstmessage");
1960 case GST_MESSAGE_BUFFERING:
1961 __mmplayer_gst_handle_buffering_message(player, msg);
1964 case GST_MESSAGE_STATE_CHANGED:
1965 __mmplayer_gst_handle_state_message(player, msg);
1968 case GST_MESSAGE_CLOCK_LOST:
1970 GstClock *clock = NULL;
1971 gboolean need_new_clock = FALSE;
1973 gst_message_parse_clock_lost(msg, &clock);
1974 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1976 if (!player->videodec_linked)
1977 need_new_clock = TRUE;
1978 else if (!player->ini.use_system_clock)
1979 need_new_clock = TRUE;
1981 if (need_new_clock) {
1982 LOGD("Provide clock is TRUE, do pause->resume");
1983 _mmplayer_gst_pause(player, FALSE);
1984 _mmplayer_gst_resume(player, FALSE);
1989 case GST_MESSAGE_NEW_CLOCK:
1991 GstClock *clock = NULL;
1992 gst_message_parse_new_clock(msg, &clock);
1993 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1997 case GST_MESSAGE_ELEMENT:
1998 __mmplayer_gst_handle_element_message(player, msg);
2001 case GST_MESSAGE_DURATION_CHANGED:
2003 LOGD("GST_MESSAGE_DURATION_CHANGED");
2004 if (!__mmplayer_gst_handle_duration(player, msg))
2005 LOGW("failed to update duration");
2009 case GST_MESSAGE_ASYNC_START:
2010 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2013 case GST_MESSAGE_ASYNC_DONE:
2014 __mmplayer_gst_handle_async_done_message(player, msg);
2016 case GST_MESSAGE_STREAM_COLLECTION:
2017 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2019 case GST_MESSAGE_STREAMS_SELECTED:
2020 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2024 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2025 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2026 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2027 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2028 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2029 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2030 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2031 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2032 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2033 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2034 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2035 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2036 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2037 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2038 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2045 /* should not call 'gst_message_unref(msg)' */
2049 static GstBusSyncReply
2050 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2052 mmplayer_t *player = (mmplayer_t *)data;
2053 GstBusSyncReply reply = GST_BUS_DROP;
2055 if (!(player->pipeline && player->pipeline->mainbin)) {
2056 LOGE("player pipeline handle is null");
2057 return GST_BUS_PASS;
2060 if (!__mmplayer_gst_check_useful_message(player, message)) {
2061 gst_message_unref(message);
2062 return GST_BUS_DROP;
2065 switch (GST_MESSAGE_TYPE(message)) {
2066 case GST_MESSAGE_TAG:
2067 __mmplayer_gst_extract_tag_from_msg(player, message);
2071 GstTagList *tags = NULL;
2073 gst_message_parse_tag(message, &tags);
2075 LOGE("TAGS received from element \"%s\".",
2076 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2078 gst_tag_list_foreach(tags, print_tag, NULL);
2079 gst_tag_list_unref(tags);
2087 case GST_MESSAGE_DURATION_CHANGED:
2088 __mmplayer_gst_handle_duration(player, message);
2090 case GST_MESSAGE_ELEMENT:
2092 const gchar *klass = NULL;
2093 klass = gst_element_factory_get_metadata
2094 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2095 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2096 reply = GST_BUS_PASS;
2099 __mmplayer_gst_handle_element_message(player, message);
2102 case GST_MESSAGE_ASYNC_DONE:
2103 /* NOTE:Don't call gst_callback directly
2104 * because previous frame can be showed even though this message is received for seek.
2107 reply = GST_BUS_PASS;
2111 if (reply == GST_BUS_DROP)
2112 gst_message_unref(message);
2118 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2120 GstElement *appsrc = element;
2121 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2122 GstBuffer *buffer = NULL;
2123 GstFlowReturn ret = GST_FLOW_OK;
2126 MMPLAYER_RETURN_IF_FAIL(element);
2127 MMPLAYER_RETURN_IF_FAIL(buf);
2129 buffer = gst_buffer_new();
2131 if (buf->offset < 0 || buf->len < 0) {
2132 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2136 if (buf->offset >= buf->len) {
2137 LOGD("call eos appsrc");
2138 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2142 if (buf->len - buf->offset < size)
2143 len = buf->len - buf->offset;
2145 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2146 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2147 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2150 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2152 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2158 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2160 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2162 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2164 buf->offset = (int)size;
2170 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2172 mmplayer_t *player = (mmplayer_t *)user_data;
2173 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2174 MMMessageParamType msg_param = {0,};
2175 guint64 current_level_bytes = 0;
2177 MMPLAYER_RETURN_IF_FAIL(player);
2179 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2180 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2181 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2182 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2184 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2188 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2190 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2192 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2193 msg_param.buffer_status.stream_type = stream_type;
2194 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2195 msg_param.buffer_status.bytes = current_level_bytes;
2197 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2201 __mmplayer_gst_appsrc_enough_data(GstElement *element, 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 enough-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_OVERFLOW;
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_seek_data(GstElement *element, guint64 position, 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,};
2238 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2240 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2241 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2242 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2243 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2245 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2249 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2251 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2252 msg_param.seek_data.stream_type = stream_type;
2253 msg_param.seek_data.offset = position;
2255 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2261 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2263 #define MAX_LEN_NAME 20
2265 gboolean ret = FALSE;
2266 GstPad *sinkpad = NULL;
2267 gchar *prefix = NULL;
2268 gchar dec_name[MAX_LEN_NAME] = {0, };
2269 main_element_id_e elem_id = MMPLAYER_M_NUM;
2271 mmplayer_gst_element_t *mainbin = NULL;
2272 GstElement *decodebin = NULL;
2273 GstCaps *dec_caps = NULL;
2277 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2279 player->pipeline->mainbin, FALSE);
2280 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2282 mainbin = player->pipeline->mainbin;
2284 case MM_PLAYER_STREAM_TYPE_AUDIO:
2286 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2288 case MM_PLAYER_STREAM_TYPE_VIDEO:
2290 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2293 LOGE("invalid type %d", type);
2297 if (mainbin[elem_id].gst) {
2298 LOGE("elem(%d) is already created", elem_id);
2302 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2304 /* create decodebin */
2305 decodebin = gst_element_factory_make("decodebin", dec_name);
2307 LOGE("failed to create %s", dec_name);
2311 mainbin[elem_id].id = elem_id;
2312 mainbin[elem_id].gst = decodebin;
2314 /* raw pad handling signal */
2315 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2316 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2318 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2319 before looking for any elements that can handle that stream.*/
2320 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2321 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2323 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2324 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2325 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2327 /* This signal is emitted when a element is added to the bin.*/
2328 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2329 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2331 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2332 LOGE("failed to add new decodebin");
2336 dec_caps = gst_pad_query_caps(srcpad, NULL);
2339 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2341 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2342 gst_caps_unref(dec_caps);
2345 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2347 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2348 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2351 gst_object_unref(GST_OBJECT(sinkpad));
2353 gst_element_sync_state_with_parent(decodebin);
2359 gst_object_unref(GST_OBJECT(sinkpad));
2361 if (mainbin[elem_id].gst) {
2362 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2363 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2364 gst_object_unref(mainbin[elem_id].gst);
2365 mainbin[elem_id].gst = NULL;
2373 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2375 #define MAX_LEN_NAME 20
2376 mmplayer_gst_element_t *mainbin = NULL;
2377 gchar *prefix = NULL;
2378 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2380 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2381 GstElement *src = NULL, *queue = NULL;
2382 GstPad *srcpad = NULL;
2385 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2386 player->pipeline->mainbin, FALSE);
2388 mainbin = player->pipeline->mainbin;
2390 LOGD("type(%d) path is creating", type);
2392 case MM_PLAYER_STREAM_TYPE_AUDIO:
2394 if (mainbin[MMPLAYER_M_SRC].gst)
2395 src_id = MMPLAYER_M_2ND_SRC;
2397 src_id = MMPLAYER_M_SRC;
2398 queue_id = MMPLAYER_M_A_BUFFER;
2400 case MM_PLAYER_STREAM_TYPE_VIDEO:
2402 src_id = MMPLAYER_M_SRC;
2403 queue_id = MMPLAYER_M_V_BUFFER;
2405 case MM_PLAYER_STREAM_TYPE_TEXT:
2406 prefix = "subtitle";
2407 src_id = MMPLAYER_M_SUBSRC;
2408 queue_id = MMPLAYER_M_S_BUFFER;
2411 LOGE("invalid type %d", type);
2415 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2416 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2419 src = gst_element_factory_make("appsrc", src_name);
2421 LOGF("failed to create %s", src_name);
2425 mainbin[src_id].id = src_id;
2426 mainbin[src_id].gst = src;
2428 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2429 "caps", caps, NULL);
2431 /* size of many video frames are larger than default blocksize as 4096 */
2432 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2433 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2435 if (player->media_stream_buffer_max_size[type] > 0)
2436 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2438 if (player->media_stream_buffer_min_percent[type] > 0)
2439 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2441 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2442 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2444 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2445 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2446 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2447 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2448 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2449 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2452 queue = gst_element_factory_make("queue2", queue_name);
2454 LOGE("failed to create %s", queue_name);
2457 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2459 mainbin[queue_id].id = queue_id;
2460 mainbin[queue_id].gst = queue;
2462 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2463 LOGE("failed to add src");
2467 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2468 LOGE("failed to add queue");
2472 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2473 LOGE("failed to link src and queue");
2477 /* create decoder */
2478 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2480 LOGE("failed to get srcpad of queue");
2484 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2485 _mmplayer_gst_create_decoder(player, srcpad, caps);
2487 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2488 LOGE("failed to create decoder");
2489 gst_object_unref(GST_OBJECT(srcpad));
2493 gst_object_unref(GST_OBJECT(srcpad));
2497 if (mainbin[src_id].gst) {
2498 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2499 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2500 gst_object_unref(mainbin[src_id].gst);
2501 mainbin[src_id].gst = NULL;
2504 if (mainbin[queue_id].gst) {
2505 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2506 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2507 gst_object_unref(mainbin[queue_id].gst);
2508 mainbin[queue_id].gst = NULL;
2515 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2517 GstPad *sinkpad = NULL;
2518 GstCaps *caps = NULL;
2519 GstElement *new_element = NULL;
2520 GstStructure *str = NULL;
2521 const gchar *name = NULL;
2523 mmplayer_t *player = (mmplayer_t *)data;
2527 MMPLAYER_RETURN_IF_FAIL(element && pad);
2528 MMPLAYER_RETURN_IF_FAIL(player &&
2530 player->pipeline->mainbin);
2532 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2533 * num_dynamic_pad will decreased after creating a sinkbin.
2535 player->num_dynamic_pad++;
2536 LOGD("stream count inc : %d", player->num_dynamic_pad);
2538 caps = gst_pad_query_caps(pad, NULL);
2539 MMPLAYER_CHECK_NULL(caps);
2541 str = gst_caps_get_structure(caps, 0);
2542 name = gst_structure_get_string(str, "media");
2544 LOGE("cannot get mimetype from structure.");
2548 if (strstr(name, "video")) {
2550 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2552 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2553 if (player->v_stream_caps) {
2554 gst_caps_unref(player->v_stream_caps);
2555 player->v_stream_caps = NULL;
2558 new_element = gst_element_factory_make("fakesink", NULL);
2559 player->num_dynamic_pad--;
2564 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2565 LOGE("failed to autoplug for caps");
2569 gst_caps_unref(caps);
2574 /* excute new_element if created*/
2576 LOGD("adding new element to pipeline");
2578 /* set state to READY before add to bin */
2579 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2581 /* add new element to the pipeline */
2582 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2583 LOGE("failed to add autoplug element to bin");
2587 /* get pad from element */
2588 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2590 LOGE("failed to get sinkpad from autoplug element");
2595 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2596 LOGE("failed to link autoplug element");
2600 gst_object_unref(sinkpad);
2603 /* run. setting PLAYING here since streamming source is live source */
2604 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2608 gst_caps_unref(caps);
2614 STATE_CHANGE_FAILED:
2616 /* FIXIT : take care if new_element has already added to pipeline */
2618 gst_object_unref(GST_OBJECT(new_element));
2621 gst_object_unref(GST_OBJECT(sinkpad));
2624 gst_caps_unref(caps);
2626 /* FIXIT : how to inform this error to MSL ????? */
2627 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2628 * then post an error to application
2633 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2635 mmplayer_t *player = (mmplayer_t *)data;
2639 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2640 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2641 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2642 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2644 * [1] audio and video will be dumped with filesink.
2645 * [2] autoplugging is done by just using pad caps.
2646 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2647 * and the video will be dumped via filesink.
2649 if (player->num_dynamic_pad == 0) {
2650 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2652 if (!_mmplayer_gst_remove_fakesink(player,
2653 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2654 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2655 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2656 * source element are not same. To overcome this situation, this function will called
2657 * several places and several times. Therefore, this is not an error case.
2662 /* create dot before error-return. for debugging */
2663 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2665 player->no_more_pad = TRUE;
2671 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2673 GstElement *element = NULL;
2674 gchar *user_agent = NULL;
2675 MMHandleType attrs = 0;
2678 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2680 /* get profile attribute */
2681 attrs = MMPLAYER_GET_ATTRS(player);
2683 LOGE("failed to get content attribute");
2687 element = gst_element_factory_make("rtspsrc", "rtsp source");
2689 LOGE("failed to create rtspsrc element");
2694 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2696 SECURE_LOGD("user_agent : %s", user_agent);
2698 /* setting property to streaming source */
2699 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2701 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2703 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2704 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2705 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2706 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2712 void __mmplayer_http_src_setup(GstElement *element, GstElement *source, gpointer data)
2714 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2716 mmplayer_t *player = (mmplayer_t *)data;
2717 MMHandleType attrs = 0;
2718 gchar *user_agent, *cookies, **cookie_list;
2719 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2720 user_agent = cookies = NULL;
2724 MMPLAYER_RETURN_IF_FAIL(player);
2726 LOGD("source element %s", GST_ELEMENT_NAME(source));
2728 /* get profile attribute */
2729 attrs = MMPLAYER_GET_ATTRS(player);
2731 LOGE("failed to get content attribute");
2735 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2736 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2739 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2740 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2742 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2743 http_timeout = player->ini.http_timeout;
2746 SECURE_LOGD("cookies : %s", cookies);
2747 SECURE_LOGD("user_agent : %s", user_agent);
2748 LOGD("timeout : %d", http_timeout);
2750 /* setting property to streaming source */
2751 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2753 /* parsing cookies */
2754 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2755 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2756 g_strfreev(cookie_list);
2760 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2766 gint __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2767 GstStream * stream, gpointer data)
2769 GstStreamType stype = gst_stream_get_stream_type (stream);
2771 if (stype & GST_STREAM_TYPE_AUDIO)
2772 LOGW("AUDIO type 0x%X", stype);
2773 else if (stype & GST_STREAM_TYPE_VIDEO)
2774 LOGW("VIDEO type 0x%X", stype);
2775 else if (stype & GST_STREAM_TYPE_TEXT)
2776 LOGW("TEXT type 0x%X", stype);
2782 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2784 gchar *factory_name = NULL;
2785 mmplayer_t *player = (mmplayer_t *)data;
2787 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
2789 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
2790 factory_name, GST_ELEMENT_NAME(element));
2792 /* keep the first typefind reference only */
2793 if (!player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {
2794 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
2795 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst = element;
2797 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2798 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
2799 } else if (g_strrstr(factory_name, "parsebin")) {
2800 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
2801 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
2802 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2803 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
2805 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2806 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
2808 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2809 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2811 _mmplayer_gst_element_added((GstElement *)child, element, data);
2818 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2820 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
2825 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
2827 GstElement *uridecodebin3 = NULL;
2828 GstElement *decodebin3 = NULL, *multiqueue = NULL;
2831 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2833 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
2834 if (!uridecodebin3) {
2835 LOGE("failed to create uridecodebin3");
2840 SECURE_LOGD("uri : %s", player->profile.uri);
2842 decodebin3 = gst_bin_get_by_name((GstBin *)uridecodebin3, "decodebin3-0");
2845 g_object_set(G_OBJECT(decodebin3), "message-forward", TRUE, NULL);
2846 multiqueue = gst_bin_get_by_name((GstBin *)decodebin3, "multiqueue0");
2850 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
2851 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = multiqueue;
2853 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
2854 _mm_player_streaming_set_multiqueue(player->streamer, multiqueue);
2857 /* setting property to streaming source */
2858 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri, "message-forward", TRUE, NULL);
2860 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2861 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "source-setup", G_CALLBACK(__mmplayer_http_src_setup), (gpointer)player);
2863 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2864 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2866 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2867 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
2869 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2870 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
2872 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2873 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
2875 /* FIXME: need to be added for gapless playback
2876 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2877 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
2880 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2881 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
2883 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2884 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
2886 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2887 LOGW("[DASH] this is still experimental feature");
2890 return uridecodebin3;
2894 __mmplayer_gst_make_http_src(mmplayer_t *player)
2896 #define MAX_RETRY_COUNT 10
2897 GstElement *element = NULL;
2898 MMHandleType attrs = 0;
2899 gchar *user_agent, *cookies, **cookie_list;
2900 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2902 user_agent = cookies = NULL;
2906 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2908 /* get profile attribute */
2909 attrs = MMPLAYER_GET_ATTRS(player);
2911 LOGE("failed to get content attribute");
2915 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2917 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2919 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2924 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2925 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2927 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2928 http_timeout = player->ini.http_timeout;
2931 SECURE_LOGD("location : %s", player->profile.uri);
2932 SECURE_LOGD("cookies : %s", cookies);
2933 SECURE_LOGD("user_agent : %s", user_agent);
2934 LOGD("timeout : %d", http_timeout);
2936 /* setting property to streaming source */
2937 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2938 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2939 "retries", MAX_RETRY_COUNT, NULL);
2941 /* parsing cookies */
2942 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2943 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2944 g_strfreev(cookie_list);
2948 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2950 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2951 LOGW("[DASH] this is still experimental feature");
2958 __mmplayer_gst_make_file_src(mmplayer_t *player)
2960 GstElement *element = NULL;
2963 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2965 LOGD("using filesrc for 'file://' handler");
2966 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2967 LOGE("failed to get storage info");
2971 element = gst_element_factory_make("filesrc", "source");
2973 LOGE("failed to create filesrc");
2977 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2984 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2986 mmplayer_t *player = (mmplayer_t *)data;
2988 g_return_val_if_fail(player, FALSE);
2989 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2991 gst_message_ref(msg);
2993 g_mutex_lock(&player->bus_msg_q_lock);
2994 g_queue_push_tail(player->bus_msg_q, msg);
2995 g_mutex_unlock(&player->bus_msg_q_lock);
2997 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2998 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2999 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3003 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3005 mmplayer_t *player = (mmplayer_t *)(data);
3006 GstMessage *msg = NULL;
3010 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3012 player->pipeline->mainbin &&
3013 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3016 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3018 LOGE("cannot get BUS from the pipeline");
3022 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3024 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3025 while (!player->bus_msg_thread_exit) {
3026 g_mutex_lock(&player->bus_msg_q_lock);
3027 msg = g_queue_pop_head(player->bus_msg_q);
3028 g_mutex_unlock(&player->bus_msg_q_lock);
3030 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3033 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3034 /* handle the gst msg */
3035 __mmplayer_gst_bus_msg_callback(msg, player);
3036 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3037 gst_message_unref(msg);
3040 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3041 gst_object_unref(GST_OBJECT(bus));
3048 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3050 gint64 dur_nsec = 0;
3053 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3055 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3056 return MM_ERROR_NONE;
3058 /* NOTE : duration cannot be zero except live streaming.
3059 * Since some element could have some timing problemn with quering duration, try again.
3061 if (player->duration == 0) {
3062 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3063 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3064 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3065 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3066 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3067 player->pending_seek.is_pending = true;
3068 player->pending_seek.pos = position;
3069 player->seek_state = MMPLAYER_SEEK_NONE;
3070 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3071 return MM_ERROR_PLAYER_NO_OP;
3073 player->seek_state = MMPLAYER_SEEK_NONE;
3074 return MM_ERROR_PLAYER_SEEK;
3077 player->duration = dur_nsec;
3080 if (player->duration > 0 && player->duration < position) {
3081 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3082 return MM_ERROR_INVALID_ARGUMENT;
3086 return MM_ERROR_NONE;
3090 __mmplayer_gst_check_seekable(mmplayer_t *player)
3092 GstQuery *query = NULL;
3093 gboolean seekable = FALSE;
3095 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3099 query = gst_query_new_seeking(GST_FORMAT_TIME);
3100 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3101 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3102 gst_query_unref(query);
3105 LOGW("non-seekable content");
3106 player->seek_state = MMPLAYER_SEEK_NONE;
3110 LOGW("failed to get seeking query");
3111 gst_query_unref(query); /* keep seeking operation */
3118 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3120 GstState element_state = GST_STATE_VOID_PENDING;
3121 GstState element_pending_state = GST_STATE_VOID_PENDING;
3122 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3127 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3129 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3132 ret = gst_element_set_state(element, state);
3133 if (ret == GST_STATE_CHANGE_FAILURE) {
3134 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3136 /* dump state of all element */
3137 _mmplayer_dump_pipeline_state(player);
3139 return MM_ERROR_PLAYER_INTERNAL;
3142 /* return here so state transition to be done in async mode */
3144 LOGD("async state transition. not waiting for state complete.");
3145 return MM_ERROR_NONE;
3148 /* wait for state transition */
3149 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3150 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3151 LOGE("failed to change [%s] element state to [%s] within %d sec",
3152 GST_ELEMENT_NAME(element),
3153 gst_element_state_get_name(state), timeout);
3155 LOGE(" [%s] state : %s pending : %s",
3156 GST_ELEMENT_NAME(element),
3157 gst_element_state_get_name(element_state),
3158 gst_element_state_get_name(element_pending_state));
3160 /* dump state of all element */
3161 _mmplayer_dump_pipeline_state(player);
3163 return MM_ERROR_PLAYER_INTERNAL;
3166 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3170 return MM_ERROR_NONE;
3174 _mmplayer_gst_start(mmplayer_t *player)
3176 int ret = MM_ERROR_NONE;
3177 gboolean async = FALSE;
3181 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3183 /* NOTE : if SetPosition was called before Start. do it now
3184 * streaming doesn't support it. so it should be always sync
3185 * !!create one more api to check if there is pending seek rather than checking variables
3187 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3188 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3189 ret = _mmplayer_gst_pause(player, FALSE);
3190 if (ret != MM_ERROR_NONE) {
3191 LOGE("failed to set state to PAUSED for pending seek");
3195 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3196 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3197 LOGW("failed to seek pending postion. starting from the begin of content");
3200 LOGD("current state before doing transition");
3201 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3202 MMPLAYER_PRINT_STATE(player);
3204 /* set pipeline state to PLAYING */
3205 ret = _mmplayer_gst_set_state(player,
3206 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3207 if (ret != MM_ERROR_NONE) {
3208 LOGE("failed to set state to PLAYING");
3212 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3214 /* generating debug info before returning error */
3215 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3223 _mmplayer_gst_stop(mmplayer_t *player)
3225 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3226 MMHandleType attrs = 0;
3227 gboolean rewind = FALSE;
3229 int ret = MM_ERROR_NONE;
3233 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3234 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3236 LOGD("current state before doing transition");
3237 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3238 MMPLAYER_PRINT_STATE(player);
3240 attrs = MMPLAYER_GET_ATTRS(player);
3242 LOGE("cannot get content attribute");
3243 return MM_ERROR_PLAYER_INTERNAL;
3246 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3247 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3249 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3250 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3253 if (player->es_player_push_mode)
3254 /* disable the async state transition because there could be no data in the pipeline */
3255 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3258 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3260 if (player->es_player_push_mode) {
3261 /* enable the async state transition as default operation */
3262 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3265 /* return if set_state has failed */
3266 if (ret != MM_ERROR_NONE) {
3267 LOGE("failed to set state.");
3273 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3274 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3275 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3276 LOGW("failed to rewind");
3277 ret = MM_ERROR_PLAYER_SEEK;
3282 player->sent_bos = FALSE;
3284 if (player->es_player_push_mode) //for cloudgame
3287 /* wait for seek to complete */
3288 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3289 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3290 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3292 LOGE("fail to stop player.");
3293 ret = MM_ERROR_PLAYER_INTERNAL;
3294 _mmplayer_dump_pipeline_state(player);
3297 /* generate dot file if enabled */
3298 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3306 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3308 int ret = MM_ERROR_NONE;
3312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3313 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3315 LOGD("current state before doing transition");
3316 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3317 MMPLAYER_PRINT_STATE(player);
3319 /* set pipeline status to PAUSED */
3320 ret = _mmplayer_gst_set_state(player,
3321 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3326 if (ret != MM_ERROR_NONE) {
3327 GstMessage *msg = NULL;
3328 GTimer *timer = NULL;
3329 gdouble MAX_TIMEOUT_SEC = 3;
3331 LOGE("failed to set state to PAUSED");
3333 if (!player->bus_watcher) {
3334 LOGE("there is no bus msg thread. pipeline is shutting down.");
3338 if (player->msg_posted) {
3339 LOGE("error msg is already posted.");
3343 timer = g_timer_new();
3344 g_timer_start(timer);
3346 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3349 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3351 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3352 GError *error = NULL;
3354 /* parse error code */
3355 gst_message_parse_error(msg, &error, NULL);
3357 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3358 /* Note : the streaming error from the streaming source is handled
3359 * using __mmplayer_handle_streaming_error.
3361 __mmplayer_handle_streaming_error(player, msg);
3364 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3366 if (error->domain == GST_STREAM_ERROR)
3367 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3368 else if (error->domain == GST_RESOURCE_ERROR)
3369 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3370 else if (error->domain == GST_LIBRARY_ERROR)
3371 ret = __mmplayer_gst_handle_library_error(player, error->code);
3372 else if (error->domain == GST_CORE_ERROR)
3373 ret = __mmplayer_gst_handle_core_error(player, error->code);
3375 g_error_free(error);
3377 player->msg_posted = TRUE;
3379 gst_message_unref(msg);
3381 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3383 gst_object_unref(bus);
3384 g_timer_stop(timer);
3385 g_timer_destroy(timer);
3390 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3391 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3392 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3393 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3396 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3399 /* generate dot file before returning error */
3400 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3408 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3410 int ret = MM_ERROR_NONE;
3415 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3416 MM_ERROR_PLAYER_NOT_INITIALIZED);
3418 LOGD("current state before doing transition");
3419 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3420 MMPLAYER_PRINT_STATE(player);
3423 LOGD("do async state transition to PLAYING");
3425 /* set pipeline state to PLAYING */
3426 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3428 ret = _mmplayer_gst_set_state(player,
3429 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3430 if (ret != MM_ERROR_NONE) {
3431 LOGE("failed to set state to PLAYING");
3436 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3439 /* generate dot file */
3440 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3447 /* sending event to one of sinkelements */
3449 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3451 GstEvent *event2 = NULL;
3452 GList *sinks = NULL;
3453 gboolean res = FALSE;
3456 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3457 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3459 /* While adding subtitles in live feeds seek is getting called.
3460 Adding defensive check in framework layer.*/
3461 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3462 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3463 LOGE("Should not send seek event during live playback");
3468 if (player->play_subtitle)
3469 event2 = gst_event_copy((const GstEvent *)event);
3471 sinks = player->sink_elements;
3473 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3475 if (GST_IS_ELEMENT(sink)) {
3476 /* keep ref to the event */
3477 gst_event_ref(event);
3479 if ((res = gst_element_send_event(sink, event))) {
3480 LOGD("sending event[%s] to sink element [%s] success!",
3481 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3483 /* rtsp case, asyn_done is not called after seek during pause state */
3484 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3485 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3486 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3487 LOGD("RTSP seek completed, after pause state..");
3488 player->seek_state = MMPLAYER_SEEK_NONE;
3489 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3495 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3496 sinks = g_list_next(sinks);
3503 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3504 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3507 sinks = g_list_next(sinks);
3510 /* Note : Textbin is not linked to the video or audio bin.
3511 * It needs to send the event to the text sink seperatelly.
3513 if (player->play_subtitle && player->pipeline) {
3514 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3516 if (GST_IS_ELEMENT(text_sink)) {
3517 /* keep ref to the event */
3518 gst_event_ref(event2);
3520 if ((res = gst_element_send_event(text_sink, event2)))
3521 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3522 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3524 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3525 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3527 gst_event_unref(event2);
3531 gst_event_unref(event);
3539 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3540 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3541 gint64 cur, GstSeekType stop_type, gint64 stop)
3543 GstEvent *event = NULL;
3544 gboolean result = FALSE;
3548 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3550 if (player->pipeline && player->pipeline->textbin)
3551 __mmplayer_drop_subtitle(player, FALSE);
3553 event = gst_event_new_seek(rate, format, flags, cur_type,
3554 cur, stop_type, stop);
3556 result = _mmplayer_gst_send_event_to_sink(player, event);
3564 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3566 int ret = MM_ERROR_NONE;
3567 gint64 pos_nsec = 0;
3568 gboolean accurated = FALSE;
3569 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3572 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3573 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3575 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3576 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3579 ret = __mmplayer_gst_check_duration(player, position);
3580 if (ret != MM_ERROR_NONE) {
3581 LOGE("failed to check duration 0x%X", ret);
3582 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3585 if (!__mmplayer_gst_check_seekable(player))
3586 return MM_ERROR_PLAYER_NO_OP;
3588 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3589 position, player->playback_rate, player->duration);
3591 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3592 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3593 This causes problem is position calculation during normal pause resume scenarios also.
3594 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3595 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3596 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3597 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3598 LOGW("getting current position failed in seek");
3600 player->last_position = pos_nsec;
3601 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3604 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3605 LOGD("not completed seek");
3606 return MM_ERROR_PLAYER_DOING_SEEK;
3609 if (!internal_called)
3610 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3612 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3613 that's why set position through property. */
3614 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3615 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3616 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3617 (!player->videodec_linked) && (!player->audiodec_linked)) {
3619 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3620 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3622 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3623 player->seek_state = MMPLAYER_SEEK_NONE;
3624 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3626 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3628 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3630 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3632 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3633 GST_FORMAT_TIME, seek_flags,
3634 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3635 LOGE("failed to set position");
3640 /* NOTE : store last seeking point to overcome some bad operation
3641 * (returning zero when getting current position) of some elements
3643 player->last_position = position;
3645 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3646 if (player->playback_rate > 1.0)
3647 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3649 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3650 LOGD("buffering should be reset after seeking");
3651 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3652 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3656 return MM_ERROR_NONE;
3659 player->pending_seek.is_pending = true;
3660 player->pending_seek.pos = position;
3662 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3663 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3664 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3665 player->pending_seek.pos);
3667 return MM_ERROR_NONE;
3670 player->seek_state = MMPLAYER_SEEK_NONE;
3671 return MM_ERROR_PLAYER_SEEK;
3675 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3677 #define TRICKPLAY_OFFSET GST_MSECOND
3679 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3680 gint64 pos_nsec = 0;
3681 gboolean ret = TRUE;
3683 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3684 MM_ERROR_PLAYER_NOT_INITIALIZED);
3686 current_state = MMPLAYER_CURRENT_STATE(player);
3688 /* NOTE : query position except paused state to overcome some bad operation
3689 * please refer to below comments in details
3691 if (current_state != MM_PLAYER_STATE_PAUSED)
3692 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3694 /* NOTE : get last point to overcome some bad operation of some elements
3695 *(returning zero when getting current position in paused state
3696 * and when failed to get postion during seeking
3698 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3699 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3701 if (player->playback_rate < 0.0)
3702 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3704 pos_nsec = player->last_position;
3707 pos_nsec = player->last_position;
3709 player->last_position = pos_nsec;
3711 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3714 if (player->duration > 0 && pos_nsec > player->duration)
3715 pos_nsec = player->duration;
3717 player->last_position = pos_nsec;
3720 *position = pos_nsec;
3722 return MM_ERROR_NONE;
3726 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3728 #define STREAMING_IS_FINISHED 0
3729 #define BUFFERING_MAX_PER 100
3730 #define DEFAULT_PER_VALUE -1
3731 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3733 mmplayer_gst_element_t *mainbin = NULL;
3734 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3735 gint64 buffered_total = 0;
3736 gint64 position = 0;
3737 gint buffered_sec = -1;
3738 GstBufferingMode mode = GST_BUFFERING_STREAM;
3739 gint64 content_size_time = player->duration;
3740 guint64 content_size_bytes = player->http_content_size;
3742 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3744 player->pipeline->mainbin,
3745 MM_ERROR_PLAYER_NOT_INITIALIZED);
3747 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3752 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3753 /* and rtsp is not ready yet. */
3754 LOGW("it's only used for http streaming case");
3755 return MM_ERROR_PLAYER_NO_OP;
3758 if (content_size_time <= 0 || content_size_bytes <= 0) {
3759 LOGW("there is no content size");
3760 return MM_ERROR_NONE;
3763 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3764 LOGW("fail to get current position");
3765 return MM_ERROR_NONE;
3768 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3769 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3771 mainbin = player->pipeline->mainbin;
3772 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3774 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3775 GstQuery *query = NULL;
3776 gint byte_in_rate = 0, byte_out_rate = 0;
3777 gint64 estimated_total = 0;
3779 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3780 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3781 LOGW("fail to get buffering query from queue2");
3783 gst_query_unref(query);
3784 return MM_ERROR_NONE;
3787 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3788 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3790 if (mode == GST_BUFFERING_STREAM) {
3791 /* using only queue in case of push mode(ts / mp3) */
3792 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3793 GST_FORMAT_BYTES, &buffered_total)) {
3794 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3795 end_per = 100 * buffered_total / content_size_bytes;
3798 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3800 guint num_of_ranges = 0;
3801 gint64 start_byte = 0, stop_byte = 0;
3803 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3804 if (estimated_total != STREAMING_IS_FINISHED) {
3805 /* buffered size info from queue2 */
3806 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3807 for (idx = 0; idx < num_of_ranges; idx++) {
3808 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3809 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3811 buffered_total += (stop_byte - start_byte);
3814 end_per = BUFFERING_MAX_PER;
3817 gst_query_unref(query);
3820 if (end_per == DEFAULT_PER_VALUE) {
3821 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3823 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3825 /* buffered size info from multiqueue */
3826 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3827 guint curr_size_bytes = 0;
3828 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3829 "curr-size-bytes", &curr_size_bytes, NULL);
3830 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3831 buffered_total += curr_size_bytes;
3834 if (avg_byterate > 0)
3835 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3836 else if (player->total_maximum_bitrate > 0)
3837 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3838 else if (player->total_bitrate > 0)
3839 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3841 if (buffered_sec >= 0)
3842 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3846 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3847 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3849 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3850 buffered_total, buffered_sec, *start_pos, *end_pos);
3852 return MM_ERROR_NONE;
3856 _mmplayer_gst_create_source(mmplayer_t *player)
3858 GstElement *element = NULL;
3861 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3862 player->pipeline->mainbin, NULL);
3864 /* setup source for gapless play */
3865 switch (player->profile.uri_type) {
3867 case MM_PLAYER_URI_TYPE_FILE:
3868 element = __mmplayer_gst_make_file_src(player);
3870 case MM_PLAYER_URI_TYPE_URL_HTTP:
3871 element = __mmplayer_gst_make_http_src(player);
3874 LOGE("not support uri type %d", player->profile.uri_type);
3879 LOGE("failed to create source element");
3888 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3891 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3892 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3894 SECURE_LOGD("uri : %s", player->profile.uri);
3896 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3898 if ((player->v_stream_caps) &&
3899 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3900 return MM_ERROR_PLAYER_INTERNAL;
3902 if ((player->a_stream_caps) &&
3903 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3904 return MM_ERROR_PLAYER_INTERNAL;
3906 if ((player->s_stream_caps) &&
3907 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3908 return MM_ERROR_PLAYER_INTERNAL;
3911 return MM_ERROR_NONE;
3915 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3917 mmplayer_gst_element_t *mainbin = NULL;
3918 GstElement *src_elem = NULL;
3919 GstElement *autoplug_elem = NULL;
3920 GList *element_bucket = NULL;
3921 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3924 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3925 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3927 mainbin = player->pipeline->mainbin;
3929 LOGD("uri type %d", player->profile.uri_type);
3931 /* create source element */
3932 switch (player->profile.uri_type) {
3933 case MM_PLAYER_URI_TYPE_URL_RTSP:
3934 src_elem = __mmplayer_gst_make_rtsp_src(player);
3936 case MM_PLAYER_URI_TYPE_URL_HTTP:
3937 if (player->ini.use_uridecodebin3) { /* or MMPLAYER_USE_URIDECODEBIN3(player) */
3938 LOGD("uridecodebin include src element.");
3941 src_elem = __mmplayer_gst_make_http_src(player);
3943 case MM_PLAYER_URI_TYPE_FILE:
3944 src_elem = __mmplayer_gst_make_file_src(player);
3946 case MM_PLAYER_URI_TYPE_SS:
3948 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3949 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3951 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3955 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3956 LOGD("get timeout from ini");
3957 http_timeout = player->ini.http_timeout;
3960 /* setting property to streaming source */
3961 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3964 case MM_PLAYER_URI_TYPE_MEM:
3966 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3968 src_elem = gst_element_factory_make("appsrc", "mem-source");
3970 LOGE("failed to create appsrc element");
3974 g_object_set(src_elem, "stream-type", stream_type,
3975 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3977 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3978 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3979 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3980 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3984 LOGE("not support uri type");
3989 LOGE("failed to create source element");
3990 return MM_ERROR_PLAYER_INTERNAL;
3993 /* take source element */
3994 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3996 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3997 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3998 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4000 ADD_DECODEBIN: /* create next element for auto-plugging */
4001 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4002 if (!src_elem) { /* make uridecodebin3 which include src element */
4003 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4004 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4005 if (!autoplug_elem) {
4006 LOGE("failed to create uridecodebin3 element");
4010 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4011 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4012 if (!autoplug_elem) {
4013 LOGE("failed to create typefind element");
4016 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4017 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4019 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4020 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4021 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4022 if (!autoplug_elem) {
4023 LOGE("failed to create decodebin");
4027 /* default size of mq in decodebin is 2M
4028 * but it can cause blocking issue during seeking depends on content. */
4029 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4032 if (autoplug_elem) {
4033 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4034 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4035 mainbin[autoplug_elem_id].gst = autoplug_elem;
4037 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4040 /* add elements to pipeline */
4041 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4042 LOGE("failed to add elements to pipeline");
4046 /* linking elements in the bucket by added order. */
4047 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4048 LOGE("failed to link some elements");
4052 /* FIXME: need to check whether this is required or not. */
4053 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4054 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4055 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4056 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4057 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4059 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4060 LOGE("failed to create fakesink");
4063 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4065 /* take ownership of fakesink. we are reusing it */
4066 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4068 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4069 LOGE("failed to add fakesink to bin");
4070 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4075 g_list_free(element_bucket);
4078 return MM_ERROR_NONE;
4081 g_list_free(element_bucket);
4083 if (mainbin[MMPLAYER_M_SRC].gst)
4084 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4086 if (mainbin[autoplug_elem_id].gst)
4087 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4089 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4090 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4092 mainbin[MMPLAYER_M_SRC].gst = NULL;
4093 mainbin[autoplug_elem_id].gst = NULL;
4094 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4096 return MM_ERROR_PLAYER_INTERNAL;
4100 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4103 mmplayer_gst_element_t *mainbin = NULL;
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4107 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4109 mainbin = player->pipeline->mainbin;
4111 /* connect bus callback */
4112 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4114 LOGE("cannot get bus from pipeline");
4115 return MM_ERROR_PLAYER_INTERNAL;
4118 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4119 player->context.thread_default = g_main_context_get_thread_default();
4120 if (player->context.thread_default == NULL) {
4121 player->context.thread_default = g_main_context_default();
4122 LOGD("thread-default context is the global default context");
4124 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4126 /* set sync handler to get tag synchronously */
4127 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4128 gst_object_unref(GST_OBJECT(bus));
4130 /* create gst bus_msb_cb thread */
4131 g_mutex_init(&player->bus_msg_thread_mutex);
4132 g_cond_init(&player->bus_msg_thread_cond);
4133 player->bus_msg_thread_exit = FALSE;
4134 player->bus_msg_thread =
4135 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4136 if (!player->bus_msg_thread) {
4137 LOGE("failed to create gst BUS msg thread");
4138 g_mutex_clear(&player->bus_msg_thread_mutex);
4139 g_cond_clear(&player->bus_msg_thread_cond);
4140 return MM_ERROR_PLAYER_INTERNAL;
4144 return MM_ERROR_NONE;
4148 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4150 mmplayer_gst_element_t *mainbin = NULL;
4151 MMMessageParamType msg_param = {0,};
4152 GstElement *element = NULL;
4153 MMHandleType attrs = 0;
4155 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4159 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4160 LOGE("player is not initialized");
4164 mainbin = player->pipeline->mainbin;
4165 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4167 attrs = MMPLAYER_GET_ATTRS(player);
4169 LOGE("fail to get attributes");
4173 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4175 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4176 LOGE("failed to parse profile");
4177 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4181 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4182 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4183 LOGE("dash or hls is not supportable");
4184 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4188 element = _mmplayer_gst_create_source(player);
4190 LOGE("no source element was created");
4194 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4195 LOGE("failed to add source element to pipeline");
4196 gst_object_unref(GST_OBJECT(element));
4201 /* take source element */
4202 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4203 mainbin[MMPLAYER_M_SRC].gst = element;
4207 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4208 if (player->streamer == NULL) {
4209 player->streamer = _mm_player_streaming_create();
4210 _mm_player_streaming_initialize(player->streamer, TRUE);
4213 elem_idx = MMPLAYER_M_TYPEFIND;
4214 element = gst_element_factory_make("typefind", "typefinder");
4215 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4216 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4218 elem_idx = MMPLAYER_M_AUTOPLUG;
4219 element = _mmplayer_gst_make_decodebin(player);
4222 /* check autoplug element is OK */
4224 LOGE("can not create element(%d)", elem_idx);
4228 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4229 LOGE("failed to add sinkbin to pipeline");
4230 gst_object_unref(GST_OBJECT(element));
4235 mainbin[elem_idx].id = elem_idx;
4236 mainbin[elem_idx].gst = element;
4238 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4239 LOGE("Failed to link src - autoplug(or typefind)");
4243 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4244 LOGE("Failed to change state of src element");
4248 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4249 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4250 LOGE("Failed to change state of decodebin");
4254 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4255 LOGE("Failed to change state of src element");
4260 player->gapless.stream_changed = TRUE;
4261 player->gapless.running = TRUE;
4267 _mmplayer_set_reconfigure_state(player, FALSE);
4268 if (!player->msg_posted) {
4269 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4270 player->msg_posted = TRUE;