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 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1013 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1014 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1016 gint64 dur_bytes = 0L;
1018 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1019 LOGE("fail to get duration.");
1021 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1022 * use file information was already set on Q2 when it was created. */
1023 _mm_player_streaming_set_queue2(player->streamer,
1024 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1025 TRUE, /* use_buffering */
1026 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1027 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1030 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1031 player->no_more_pad = TRUE;
1032 _mmplayer_pipeline_complete(NULL, player);
1045 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1047 guint64 data_size = 0;
1048 gint64 pos_nsec = 0;
1050 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1052 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1054 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1055 data_size = player->http_content_size;
1058 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1059 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1065 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1067 int ret = MM_ERROR_NONE;
1068 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1069 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1070 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1071 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1073 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1074 LOGW("do nothing for buffering msg");
1075 ret = MM_ERROR_PLAYER_INVALID_STATE;
1079 prev_state = MMPLAYER_PREV_STATE(player);
1080 current_state = MMPLAYER_CURRENT_STATE(player);
1081 target_state = MMPLAYER_TARGET_STATE(player);
1082 pending_state = MMPLAYER_PENDING_STATE(player);
1084 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1085 MMPLAYER_STATE_GET_NAME(prev_state),
1086 MMPLAYER_STATE_GET_NAME(current_state),
1087 MMPLAYER_STATE_GET_NAME(pending_state),
1088 MMPLAYER_STATE_GET_NAME(target_state),
1089 player->streamer->buffering_state);
1091 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1092 /* NOTE : if buffering has done, player has to go to target state. */
1093 switch (target_state) {
1094 case MM_PLAYER_STATE_PAUSED:
1096 switch (pending_state) {
1097 case MM_PLAYER_STATE_PLAYING:
1098 _mmplayer_gst_pause(player, TRUE);
1101 case MM_PLAYER_STATE_PAUSED:
1102 LOGD("player is already going to paused state, there is nothing to do.");
1105 case MM_PLAYER_STATE_NONE:
1106 case MM_PLAYER_STATE_NULL:
1107 case MM_PLAYER_STATE_READY:
1109 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1115 case MM_PLAYER_STATE_PLAYING:
1117 switch (pending_state) {
1118 case MM_PLAYER_STATE_NONE:
1120 if (current_state != MM_PLAYER_STATE_PLAYING)
1121 _mmplayer_gst_resume(player, TRUE);
1125 case MM_PLAYER_STATE_PAUSED:
1126 /* NOTE: It should be worked as asynchronously.
1127 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1129 if (current_state == MM_PLAYER_STATE_PLAYING) {
1130 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1131 * The current state should be changed to paused purposely to prevent state conflict.
1133 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1135 _mmplayer_gst_resume(player, TRUE);
1138 case MM_PLAYER_STATE_PLAYING:
1139 LOGD("player is already going to playing state, there is nothing to do.");
1142 case MM_PLAYER_STATE_NULL:
1143 case MM_PLAYER_STATE_READY:
1145 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1151 case MM_PLAYER_STATE_NULL:
1152 case MM_PLAYER_STATE_READY:
1153 case MM_PLAYER_STATE_NONE:
1155 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1159 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1160 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1162 switch (pending_state) {
1163 case MM_PLAYER_STATE_NONE:
1165 if (current_state != MM_PLAYER_STATE_PAUSED) {
1166 /* rtsp streaming pause makes rtsp server stop sending data. */
1167 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1168 LOGD("set pause state during buffering");
1169 _mmplayer_gst_pause(player, TRUE);
1175 case MM_PLAYER_STATE_PLAYING:
1176 /* rtsp streaming pause makes rtsp server stop sending data. */
1177 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1178 _mmplayer_gst_pause(player, TRUE);
1181 case MM_PLAYER_STATE_PAUSED:
1184 case MM_PLAYER_STATE_NULL:
1185 case MM_PLAYER_STATE_READY:
1187 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1196 static stream_variant_t *
1197 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1199 stream_variant_t *var_info = NULL;
1200 g_return_val_if_fail(self != NULL, NULL);
1202 var_info = g_new0(stream_variant_t, 1);
1203 if (!var_info) return NULL;
1204 var_info->bandwidth = self->bandwidth;
1205 var_info->width = self->width;
1206 var_info->height = self->height;
1211 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1217 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1218 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1220 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1221 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1222 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1224 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1225 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1226 player->http_content_size = (bytes > 0) ? bytes : 0;
1229 /* handling audio clip which has vbr. means duration is keep changing */
1230 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1239 __mmplayer_eos_timer_cb(gpointer u_data)
1241 mmplayer_t *player = NULL;
1242 MMHandleType attrs = 0;
1245 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1247 player = (mmplayer_t *)u_data;
1248 attrs = MMPLAYER_GET_ATTRS(player);
1250 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1254 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1255 if (ret_value != MM_ERROR_NONE)
1256 LOGE("seeking to 0 failed in repeat play");
1259 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1262 /* we are returning FALSE as we need only one posting */
1267 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1269 MMPLAYER_RETURN_IF_FAIL(player);
1271 /* post now if delay is zero */
1272 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1273 LOGD("eos delay is zero. posting EOS now");
1274 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1276 if (player->audio_decoded_cb)
1277 _mmplayer_cancel_eos_timer(player);
1282 /* cancel if existing */
1283 _mmplayer_cancel_eos_timer(player);
1285 /* init new timeout */
1286 /* NOTE : consider give high priority to this timer */
1287 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1289 player->eos_timer = g_timeout_add(delay_in_ms,
1290 __mmplayer_eos_timer_cb, player);
1292 player->context.global_default = g_main_context_default();
1293 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1295 /* check timer is valid. if not, send EOS now */
1296 if (player->eos_timer == 0) {
1297 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1298 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1303 __mmplayer_gst_pending_seek(mmplayer_t *player)
1305 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1306 int ret = MM_ERROR_NONE;
1310 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1312 if (!player->pending_seek.is_pending) {
1313 LOGD("pending seek is not reserved. nothing to do.");
1317 /* check player state if player could pending seek or not. */
1318 current_state = MMPLAYER_CURRENT_STATE(player);
1320 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1321 LOGW("try to pending seek in %s state, try next time. ",
1322 MMPLAYER_STATE_GET_NAME(current_state));
1326 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1328 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1329 if (ret != MM_ERROR_NONE)
1330 LOGE("failed to seek pending postion. just keep staying current position.");
1332 player->pending_seek.is_pending = false;
1340 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1342 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1344 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1346 audiobin = player->pipeline->audiobin; /* can be null */
1347 videobin = player->pipeline->videobin; /* can be null */
1348 textbin = player->pipeline->textbin; /* can be null */
1350 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1352 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1353 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1355 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1356 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1358 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1359 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1365 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1367 mmplayer_gst_element_t *textbin;
1370 MMPLAYER_RETURN_IF_FAIL(player &&
1372 player->pipeline->textbin);
1374 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1376 textbin = player->pipeline->textbin;
1379 LOGD("Drop subtitle text after getting EOS");
1381 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1382 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1384 player->is_subtitle_force_drop = TRUE;
1386 if (player->is_subtitle_force_drop == TRUE) {
1387 LOGD("Enable subtitle data path without drop");
1389 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1390 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1392 LOGD("non-connected with external display");
1394 player->is_subtitle_force_drop = FALSE;
1400 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1402 MMHandleType attrs = 0;
1407 /* NOTE : EOS event is comming multiple time. watch out it */
1408 /* check state. we only process EOS when pipeline state goes to PLAYING */
1409 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1410 LOGD("EOS received on non-playing state. ignoring it");
1414 if (player->pipeline && player->pipeline->textbin)
1415 __mmplayer_drop_subtitle(player, TRUE);
1417 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1418 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1420 /* rewind if repeat count is greater then zero */
1421 /* get play count */
1422 attrs = MMPLAYER_GET_ATTRS(player);
1424 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1426 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1428 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1429 if (player->playback_rate < 0.0) {
1430 player->resumed_by_rewind = TRUE;
1431 _mmplayer_set_mute((MMHandleType)player, false);
1432 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1435 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1438 player->sent_bos = FALSE;
1440 LOGD("do not post eos msg for repeating");
1445 if (player->pipeline)
1446 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1448 /* post eos message to application */
1449 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1451 /* reset last position */
1452 player->last_position = 0;
1459 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1461 GError *error = NULL;
1462 gchar *debug = NULL;
1466 /* generating debug info before returning error */
1467 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1469 /* get error code */
1470 gst_message_parse_error(msg, &error, &debug);
1472 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1473 /* Note : the streaming error from the streaming source is handled
1474 * using __mmplayer_handle_streaming_error.
1476 __mmplayer_handle_streaming_error(player, msg);
1478 /* dump state of all element */
1479 _mmplayer_dump_pipeline_state(player);
1481 /* traslate gst error code to msl error code. then post it
1482 * to application if needed
1484 __mmplayer_handle_gst_error(player, msg, error);
1487 LOGE("error debug : %s", debug);
1490 MMPLAYER_FREEIF(debug);
1491 g_error_free(error);
1498 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1500 MMMessageParamType msg_param = {0, };
1501 int bRet = MM_ERROR_NONE;
1504 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1506 if (!MMPLAYER_IS_STREAMING(player)) {
1507 LOGW("this is not streaming playback.");
1511 MMPLAYER_CMD_LOCK(player);
1513 if (!player->streamer) {
1514 LOGW("Pipeline is shutting down");
1515 MMPLAYER_CMD_UNLOCK(player);
1519 /* ignore the remained buffering message till getting 100% msg */
1520 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1521 gint buffer_percent = 0;
1523 gst_message_parse_buffering(msg, &buffer_percent);
1525 if (buffer_percent == MAX_BUFFER_PERCENT) {
1526 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1527 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1528 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1530 MMPLAYER_CMD_UNLOCK(player);
1534 /* ignore the remained buffering message */
1535 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1536 gint buffer_percent = 0;
1538 gst_message_parse_buffering(msg, &buffer_percent);
1540 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1541 player->streamer->buffering_percent, buffer_percent);
1543 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1544 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1545 player->streamer->buffering_req.is_pre_buffering = FALSE;
1547 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1549 LOGD("interrupted buffering - ignored the remained buffering msg!");
1550 MMPLAYER_CMD_UNLOCK(player);
1555 __mmplayer_update_buffer_setting(player, msg);
1557 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1559 if (bRet == MM_ERROR_NONE) {
1560 msg_param.connection.buffering = player->streamer->buffering_percent;
1561 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1563 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1564 player->pending_resume &&
1565 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1567 player->is_external_subtitle_added_now = FALSE;
1568 player->pending_resume = FALSE;
1569 _mmplayer_resume((MMHandleType)player);
1572 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1573 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1575 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1576 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1577 player->seek_state = MMPLAYER_SEEK_NONE;
1578 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1579 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1580 /* Considering the async state trasition in case of RTSP.
1581 After getting state change gst msg, seek cmpleted msg will be posted. */
1582 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1586 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1587 if (!player->streamer) {
1588 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1589 MMPLAYER_CMD_UNLOCK(player);
1593 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1595 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1596 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1598 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1599 msg_param.connection.buffering = player->streamer->buffering_percent;
1600 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1602 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1605 msg_param.connection.buffering = player->streamer->buffering_percent;
1606 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1609 MMPLAYER_CMD_UNLOCK(player);
1617 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1619 mmplayer_gst_element_t *mainbin;
1620 const GValue *voldstate, *vnewstate, *vpending;
1621 GstState oldstate = GST_STATE_NULL;
1622 GstState newstate = GST_STATE_NULL;
1623 GstState pending = GST_STATE_NULL;
1626 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1628 mainbin = player->pipeline->mainbin;
1630 /* we only handle messages from pipeline */
1631 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1634 /* get state info from msg */
1635 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1636 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1637 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1639 if (!voldstate || !vnewstate) {
1640 LOGE("received msg has wrong format.");
1644 oldstate = (GstState)voldstate->data[0].v_int;
1645 newstate = (GstState)vnewstate->data[0].v_int;
1647 pending = (GstState)vpending->data[0].v_int;
1649 LOGD("state changed [%s] : %s ---> %s final : %s",
1650 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1651 gst_element_state_get_name((GstState)oldstate),
1652 gst_element_state_get_name((GstState)newstate),
1653 gst_element_state_get_name((GstState)pending));
1655 if (newstate == GST_STATE_PLAYING) {
1656 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1658 int retVal = MM_ERROR_NONE;
1659 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1661 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1663 if (MM_ERROR_NONE != retVal)
1664 LOGE("failed to seek pending postion. just keep staying current position.");
1666 player->pending_seek.is_pending = false;
1670 if (oldstate == newstate) {
1671 LOGD("pipeline reports state transition to old state");
1676 case GST_STATE_PAUSED:
1678 gboolean prepare_async = FALSE;
1680 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1681 // managed prepare async case
1682 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1683 LOGD("checking prepare mode for async transition - %d", prepare_async);
1686 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1687 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1689 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1690 _mm_player_streaming_set_content_bitrate(player->streamer,
1691 player->total_maximum_bitrate, player->total_bitrate);
1693 if (player->pending_seek.is_pending) {
1694 LOGW("trying to do pending seek");
1695 MMPLAYER_CMD_LOCK(player);
1696 __mmplayer_gst_pending_seek(player);
1697 MMPLAYER_CMD_UNLOCK(player);
1703 case GST_STATE_PLAYING:
1705 if (MMPLAYER_IS_STREAMING(player)) {
1706 // managed prepare async case when buffering is completed
1707 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1708 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1709 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1710 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1712 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1714 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1715 if (player->streamer->buffering_percent < 100) {
1717 MMMessageParamType msg_param = {0, };
1718 LOGW("Posting Buffering Completed Message to Application !!!");
1720 msg_param.connection.buffering = 100;
1721 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1726 if (player->gapless.stream_changed) {
1727 _mmplayer_update_content_attrs(player, ATTR_ALL);
1728 player->gapless.stream_changed = FALSE;
1731 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1732 player->seek_state = MMPLAYER_SEEK_NONE;
1733 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1737 case GST_STATE_VOID_PENDING:
1738 case GST_STATE_NULL:
1739 case GST_STATE_READY:
1749 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1751 const gchar *structure_name;
1752 gint count = 0, idx = 0;
1755 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1757 if (gst_message_get_structure(msg) == NULL)
1760 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1761 if (!structure_name)
1764 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1766 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1767 const GValue *var_info = NULL;
1769 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1770 if (var_info != NULL) {
1771 if (player->adaptive_info.var_list)
1772 g_list_free_full(player->adaptive_info.var_list, g_free);
1774 /* share addr or copy the list */
1775 player->adaptive_info.var_list =
1776 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1778 count = g_list_length(player->adaptive_info.var_list);
1780 stream_variant_t *temp = NULL;
1782 /* print out for debug */
1783 LOGD("num of variant_info %d", count);
1784 for (idx = 0; idx < count; idx++) {
1785 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1787 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1793 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1794 gint num_buffers = 0;
1795 gint extra_num_buffers = 0;
1797 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1798 LOGD("video_num_buffers : %d", num_buffers);
1799 mm_player_set_attribute((MMHandleType)player, NULL,
1800 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1803 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1804 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1805 mm_player_set_attribute((MMHandleType)player, NULL,
1806 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1811 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1812 _mmplayer_track_update_text_attr_info(player, msg);
1814 /* custom message */
1815 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1816 MMMessageParamType msg_param = {0,};
1817 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1818 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1821 /* custom message for RTSP attribute :
1822 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1823 sdp which has contents info is received when rtsp connection is opened.
1824 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1825 if (!strcmp(structure_name, "rtspsrc_properties")) {
1826 gchar *audio_codec = NULL;
1827 gchar *video_codec = NULL;
1828 gchar *video_frame_size = NULL;
1830 gst_structure_get(gst_message_get_structure(msg),
1831 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1832 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1833 player->streaming_type = _mmplayer_get_stream_service_type(player);
1835 gst_structure_get(gst_message_get_structure(msg),
1836 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1837 LOGD("rtsp_audio_codec : %s", audio_codec);
1839 mm_player_set_attribute((MMHandleType)player, NULL,
1840 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1842 gst_structure_get(gst_message_get_structure(msg),
1843 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1844 LOGD("rtsp_video_codec : %s", video_codec);
1846 mm_player_set_attribute((MMHandleType)player, NULL,
1847 "content_video_codec", video_codec, strlen(video_codec), NULL);
1849 gst_structure_get(gst_message_get_structure(msg),
1850 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1851 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1852 if (video_frame_size) {
1853 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1854 mm_player_set_attribute((MMHandleType)player, NULL,
1855 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1856 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1858 g_strfreev(res_str);
1867 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1869 mmplayer_gst_element_t *mainbin;
1872 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1874 mainbin = player->pipeline->mainbin;
1876 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1878 /* we only handle messages from pipeline */
1879 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1882 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1883 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1884 player->seek_state = MMPLAYER_SEEK_NONE;
1885 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1886 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1887 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1888 LOGD("sync %s state(%s) with parent state(%s)",
1889 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1890 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1891 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1893 /* In case of streaming, pause is required before finishing seeking by buffering.
1894 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1895 Because the buffering state is controlled according to the state transition for force resume,
1896 the decodebin state should be paused as player state. */
1897 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1900 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1901 (player->streamer) &&
1902 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1903 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1904 GstQuery *query = NULL;
1905 gboolean busy = FALSE;
1908 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1909 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1910 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1911 gst_query_parse_buffering_percent(query, &busy, &percent);
1912 gst_query_unref(query);
1914 LOGD("buffered percent(%s): %d",
1915 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1919 __mmplayer_handle_buffering_playback(player);
1922 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1931 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1933 mmplayer_t *player = (mmplayer_t *)(data);
1935 MMPLAYER_RETURN_IF_FAIL(player);
1936 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1938 switch (GST_MESSAGE_TYPE(msg)) {
1939 case GST_MESSAGE_UNKNOWN:
1940 LOGD("unknown message received");
1943 case GST_MESSAGE_EOS:
1944 LOGD("GST_MESSAGE_EOS received");
1945 __mmplayer_gst_handle_eos_message(player, msg);
1948 case GST_MESSAGE_ERROR:
1949 _mmplayer_set_reconfigure_state(player, FALSE);
1950 __mmplayer_gst_handle_error_message(player, msg);
1953 case GST_MESSAGE_WARNING:
1956 GError *error = NULL;
1958 gst_message_parse_warning(msg, &error, &debug);
1960 LOGD("warning : %s", error->message);
1961 LOGD("debug : %s", debug);
1963 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1965 MMPLAYER_FREEIF(debug);
1966 g_error_free(error);
1970 case GST_MESSAGE_TAG:
1972 LOGD("GST_MESSAGE_TAG");
1973 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1974 LOGW("failed to extract tags from gstmessage");
1978 case GST_MESSAGE_BUFFERING:
1979 __mmplayer_gst_handle_buffering_message(player, msg);
1982 case GST_MESSAGE_STATE_CHANGED:
1983 __mmplayer_gst_handle_state_message(player, msg);
1986 case GST_MESSAGE_CLOCK_LOST:
1988 GstClock *clock = NULL;
1989 gboolean need_new_clock = FALSE;
1991 gst_message_parse_clock_lost(msg, &clock);
1992 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1994 if (!player->videodec_linked)
1995 need_new_clock = TRUE;
1996 else if (!player->ini.use_system_clock)
1997 need_new_clock = TRUE;
1999 if (need_new_clock) {
2000 LOGD("Provide clock is TRUE, do pause->resume");
2001 _mmplayer_gst_pause(player, FALSE);
2002 _mmplayer_gst_resume(player, FALSE);
2007 case GST_MESSAGE_NEW_CLOCK:
2009 GstClock *clock = NULL;
2010 gst_message_parse_new_clock(msg, &clock);
2011 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2015 case GST_MESSAGE_ELEMENT:
2016 __mmplayer_gst_handle_element_message(player, msg);
2019 case GST_MESSAGE_DURATION_CHANGED:
2021 LOGD("GST_MESSAGE_DURATION_CHANGED");
2022 if (!__mmplayer_gst_handle_duration(player, msg))
2023 LOGW("failed to update duration");
2027 case GST_MESSAGE_ASYNC_START:
2028 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2031 case GST_MESSAGE_ASYNC_DONE:
2032 __mmplayer_gst_handle_async_done_message(player, msg);
2034 case GST_MESSAGE_STREAM_COLLECTION:
2035 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2037 case GST_MESSAGE_STREAMS_SELECTED:
2038 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2042 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2043 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2044 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2045 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2046 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2047 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2048 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2049 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2050 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2051 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2052 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2053 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2054 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2055 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2056 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2063 /* should not call 'gst_message_unref(msg)' */
2067 static GstBusSyncReply
2068 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2070 mmplayer_t *player = (mmplayer_t *)data;
2071 GstBusSyncReply reply = GST_BUS_DROP;
2073 if (!(player->pipeline && player->pipeline->mainbin)) {
2074 LOGE("player pipeline handle is null");
2075 return GST_BUS_PASS;
2078 if (!__mmplayer_gst_check_useful_message(player, message)) {
2079 gst_message_unref(message);
2080 return GST_BUS_DROP;
2083 switch (GST_MESSAGE_TYPE(message)) {
2084 case GST_MESSAGE_TAG:
2085 __mmplayer_gst_extract_tag_from_msg(player, message);
2089 GstTagList *tags = NULL;
2091 gst_message_parse_tag(message, &tags);
2093 LOGE("TAGS received from element \"%s\".",
2094 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2096 gst_tag_list_foreach(tags, print_tag, NULL);
2097 gst_tag_list_unref(tags);
2105 case GST_MESSAGE_DURATION_CHANGED:
2106 __mmplayer_gst_handle_duration(player, message);
2108 case GST_MESSAGE_ELEMENT:
2110 const gchar *klass = NULL;
2111 klass = gst_element_factory_get_metadata
2112 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2113 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2114 reply = GST_BUS_PASS;
2117 __mmplayer_gst_handle_element_message(player, message);
2120 case GST_MESSAGE_ASYNC_DONE:
2121 /* NOTE:Don't call gst_callback directly
2122 * because previous frame can be showed even though this message is received for seek.
2125 reply = GST_BUS_PASS;
2129 if (reply == GST_BUS_DROP)
2130 gst_message_unref(message);
2136 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2138 GstElement *appsrc = element;
2139 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2140 GstBuffer *buffer = NULL;
2141 GstFlowReturn ret = GST_FLOW_OK;
2144 MMPLAYER_RETURN_IF_FAIL(element);
2145 MMPLAYER_RETURN_IF_FAIL(buf);
2147 buffer = gst_buffer_new();
2149 if (buf->offset < 0 || buf->len < 0) {
2150 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2154 if (buf->offset >= buf->len) {
2155 LOGD("call eos appsrc");
2156 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2160 if (buf->len - buf->offset < size)
2161 len = buf->len - buf->offset;
2163 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2164 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2165 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2168 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2170 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2176 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2178 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2180 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2182 buf->offset = (int)size;
2188 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2190 mmplayer_t *player = (mmplayer_t *)user_data;
2191 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2192 MMMessageParamType msg_param = {0,};
2193 guint64 current_level_bytes = 0;
2195 MMPLAYER_RETURN_IF_FAIL(player);
2197 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2198 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2199 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2200 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2202 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2206 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2208 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2210 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2211 msg_param.buffer_status.stream_type = stream_type;
2212 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2213 msg_param.buffer_status.bytes = current_level_bytes;
2215 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2219 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2221 mmplayer_t *player = (mmplayer_t *)user_data;
2222 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2223 MMMessageParamType msg_param = {0,};
2224 guint64 current_level_bytes = 0;
2226 MMPLAYER_RETURN_IF_FAIL(player);
2228 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2229 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2230 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2231 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2233 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2237 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2239 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2241 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2242 msg_param.buffer_status.stream_type = stream_type;
2243 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2244 msg_param.buffer_status.bytes = current_level_bytes;
2246 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2250 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2252 mmplayer_t *player = (mmplayer_t *)user_data;
2253 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2254 MMMessageParamType msg_param = {0,};
2256 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2258 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2259 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2260 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2261 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2263 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2267 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2269 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2270 msg_param.seek_data.stream_type = stream_type;
2271 msg_param.seek_data.offset = position;
2273 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2279 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2281 #define MAX_LEN_NAME 20
2283 gboolean ret = FALSE;
2284 GstPad *sinkpad = NULL;
2285 gchar *prefix = NULL;
2286 gchar dec_name[MAX_LEN_NAME] = {0, };
2287 main_element_id_e elem_id = MMPLAYER_M_NUM;
2289 mmplayer_gst_element_t *mainbin = NULL;
2290 GstElement *decodebin = NULL;
2291 GstCaps *dec_caps = NULL;
2295 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2297 player->pipeline->mainbin, FALSE);
2298 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2300 mainbin = player->pipeline->mainbin;
2302 case MM_PLAYER_STREAM_TYPE_AUDIO:
2304 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2306 case MM_PLAYER_STREAM_TYPE_VIDEO:
2308 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2311 LOGE("invalid type %d", type);
2315 if (mainbin[elem_id].gst) {
2316 LOGE("elem(%d) is already created", elem_id);
2320 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2322 /* create decodebin */
2323 decodebin = gst_element_factory_make("decodebin", dec_name);
2325 LOGE("failed to create %s", dec_name);
2329 mainbin[elem_id].id = elem_id;
2330 mainbin[elem_id].gst = decodebin;
2332 /* raw pad handling signal */
2333 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2334 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2336 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2337 before looking for any elements that can handle that stream.*/
2338 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2339 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2341 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2342 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2343 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2345 /* This signal is emitted when a element is added to the bin.*/
2346 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2347 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2349 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2350 LOGE("failed to add new decodebin");
2354 dec_caps = gst_pad_query_caps(srcpad, NULL);
2357 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2359 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2360 gst_caps_unref(dec_caps);
2363 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2365 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2366 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2369 gst_object_unref(GST_OBJECT(sinkpad));
2371 gst_element_sync_state_with_parent(decodebin);
2377 gst_object_unref(GST_OBJECT(sinkpad));
2379 if (mainbin[elem_id].gst) {
2380 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2381 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2382 gst_object_unref(mainbin[elem_id].gst);
2383 mainbin[elem_id].gst = NULL;
2391 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2393 #define MAX_LEN_NAME 20
2394 mmplayer_gst_element_t *mainbin = NULL;
2395 gchar *prefix = NULL;
2396 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2398 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2399 GstElement *src = NULL, *queue = NULL;
2400 GstPad *srcpad = NULL;
2403 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2404 player->pipeline->mainbin, FALSE);
2406 mainbin = player->pipeline->mainbin;
2408 LOGD("type(%d) path is creating", type);
2410 case MM_PLAYER_STREAM_TYPE_AUDIO:
2412 if (mainbin[MMPLAYER_M_SRC].gst)
2413 src_id = MMPLAYER_M_2ND_SRC;
2415 src_id = MMPLAYER_M_SRC;
2416 queue_id = MMPLAYER_M_A_BUFFER;
2418 case MM_PLAYER_STREAM_TYPE_VIDEO:
2420 src_id = MMPLAYER_M_SRC;
2421 queue_id = MMPLAYER_M_V_BUFFER;
2423 case MM_PLAYER_STREAM_TYPE_TEXT:
2424 prefix = "subtitle";
2425 src_id = MMPLAYER_M_SUBSRC;
2426 queue_id = MMPLAYER_M_S_BUFFER;
2429 LOGE("invalid type %d", type);
2433 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2434 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2437 src = gst_element_factory_make("appsrc", src_name);
2439 LOGF("failed to create %s", src_name);
2443 mainbin[src_id].id = src_id;
2444 mainbin[src_id].gst = src;
2446 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2447 "caps", caps, NULL);
2449 /* size of many video frames are larger than default blocksize as 4096 */
2450 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2451 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2453 if (player->media_stream_buffer_max_size[type] > 0)
2454 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2456 if (player->media_stream_buffer_min_percent[type] > 0)
2457 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2459 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2460 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2462 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2463 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2464 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2465 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2466 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2467 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2470 queue = gst_element_factory_make("queue2", queue_name);
2472 LOGE("failed to create %s", queue_name);
2475 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2477 mainbin[queue_id].id = queue_id;
2478 mainbin[queue_id].gst = queue;
2480 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2481 LOGE("failed to add src");
2485 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2486 LOGE("failed to add queue");
2490 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2491 LOGE("failed to link src and queue");
2495 /* create decoder */
2496 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2498 LOGE("failed to get srcpad of queue");
2502 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2503 _mmplayer_gst_create_decoder(player, srcpad, caps);
2505 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2506 LOGE("failed to create decoder");
2507 gst_object_unref(GST_OBJECT(srcpad));
2511 gst_object_unref(GST_OBJECT(srcpad));
2515 if (mainbin[src_id].gst) {
2516 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2517 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2518 gst_object_unref(mainbin[src_id].gst);
2519 mainbin[src_id].gst = NULL;
2522 if (mainbin[queue_id].gst) {
2523 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2524 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2525 gst_object_unref(mainbin[queue_id].gst);
2526 mainbin[queue_id].gst = NULL;
2533 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2535 GstPad *sinkpad = NULL;
2536 GstCaps *caps = NULL;
2537 GstElement *new_element = NULL;
2538 GstStructure *str = NULL;
2539 const gchar *name = NULL;
2541 mmplayer_t *player = (mmplayer_t *)data;
2545 MMPLAYER_RETURN_IF_FAIL(element && pad);
2546 MMPLAYER_RETURN_IF_FAIL(player &&
2548 player->pipeline->mainbin);
2550 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2551 * num_dynamic_pad will decreased after creating a sinkbin.
2553 player->num_dynamic_pad++;
2554 LOGD("stream count inc : %d", player->num_dynamic_pad);
2556 caps = gst_pad_query_caps(pad, NULL);
2557 MMPLAYER_CHECK_NULL(caps);
2559 str = gst_caps_get_structure(caps, 0);
2560 name = gst_structure_get_string(str, "media");
2562 LOGE("cannot get mimetype from structure.");
2566 if (strstr(name, "video")) {
2568 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2570 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2571 if (player->v_stream_caps) {
2572 gst_caps_unref(player->v_stream_caps);
2573 player->v_stream_caps = NULL;
2576 new_element = gst_element_factory_make("fakesink", NULL);
2577 player->num_dynamic_pad--;
2582 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2583 LOGE("failed to autoplug for caps");
2587 gst_caps_unref(caps);
2592 /* excute new_element if created*/
2594 LOGD("adding new element to pipeline");
2596 /* set state to READY before add to bin */
2597 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2599 /* add new element to the pipeline */
2600 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2601 LOGE("failed to add autoplug element to bin");
2605 /* get pad from element */
2606 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2608 LOGE("failed to get sinkpad from autoplug element");
2613 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2614 LOGE("failed to link autoplug element");
2618 gst_object_unref(sinkpad);
2621 /* run. setting PLAYING here since streamming source is live source */
2622 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2626 gst_caps_unref(caps);
2632 STATE_CHANGE_FAILED:
2634 /* FIXIT : take care if new_element has already added to pipeline */
2636 gst_object_unref(GST_OBJECT(new_element));
2639 gst_object_unref(GST_OBJECT(sinkpad));
2642 gst_caps_unref(caps);
2644 /* FIXIT : how to inform this error to MSL ????? */
2645 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2646 * then post an error to application
2651 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2653 mmplayer_t *player = (mmplayer_t *)data;
2657 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2658 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2659 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2660 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2662 * [1] audio and video will be dumped with filesink.
2663 * [2] autoplugging is done by just using pad caps.
2664 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2665 * and the video will be dumped via filesink.
2667 if (player->num_dynamic_pad == 0) {
2668 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2670 if (!_mmplayer_gst_remove_fakesink(player,
2671 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2672 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2673 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2674 * source element are not same. To overcome this situation, this function will called
2675 * several places and several times. Therefore, this is not an error case.
2680 /* create dot before error-return. for debugging */
2681 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2683 player->no_more_pad = TRUE;
2689 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2691 GstElement *element = NULL;
2692 gchar *user_agent = NULL;
2693 MMHandleType attrs = 0;
2696 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2698 /* get profile attribute */
2699 attrs = MMPLAYER_GET_ATTRS(player);
2701 LOGE("failed to get content attribute");
2705 element = gst_element_factory_make("rtspsrc", "rtsp source");
2707 LOGE("failed to create rtspsrc element");
2712 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2714 SECURE_LOGD("user_agent : %s", user_agent);
2716 /* setting property to streaming source */
2717 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2719 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2721 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2722 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2723 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2724 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2730 void __mmplayer_http_src_setup(GstElement *element, GstElement *source, gpointer data)
2732 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2734 mmplayer_t *player = (mmplayer_t *)data;
2735 MMHandleType attrs = 0;
2736 gchar *user_agent, *cookies, **cookie_list;
2737 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2738 user_agent = cookies = NULL;
2742 MMPLAYER_RETURN_IF_FAIL(player);
2744 LOGD("source element %s", GST_ELEMENT_NAME(source));
2746 /* get profile attribute */
2747 attrs = MMPLAYER_GET_ATTRS(player);
2749 LOGE("failed to get content attribute");
2753 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2754 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2757 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2758 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2760 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2761 http_timeout = player->ini.http_timeout;
2764 SECURE_LOGD("cookies : %s", cookies);
2765 SECURE_LOGD("user_agent : %s", user_agent);
2766 LOGD("timeout : %d", http_timeout);
2768 /* setting property to streaming source */
2769 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2771 /* parsing cookies */
2772 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2773 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2774 g_strfreev(cookie_list);
2778 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2784 gint __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2785 GstStream * stream, gpointer data)
2787 GstStreamType stype = gst_stream_get_stream_type (stream);
2789 if (stype & GST_STREAM_TYPE_AUDIO)
2790 LOGW("AUDIO type 0x%X", stype);
2791 else if (stype & GST_STREAM_TYPE_VIDEO)
2792 LOGW("VIDEO type 0x%X", stype);
2793 else if (stype & GST_STREAM_TYPE_TEXT)
2794 LOGW("TEXT type 0x%X", stype);
2800 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2802 gchar *factory_name = NULL;
2803 mmplayer_t *player = (mmplayer_t *)data;
2804 mmplayer_gst_element_t *mainbin = NULL;
2807 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2809 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
2810 mainbin = player->pipeline->mainbin;
2812 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
2813 factory_name, GST_ELEMENT_NAME(element));
2815 /* keep the first typefind reference only */
2816 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {
2817 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
2818 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
2820 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2821 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
2823 } else if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst && g_strrstr(factory_name, "queue2")) {
2825 gint64 dur_bytes = 0L;
2826 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
2828 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
2829 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
2831 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
2832 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
2834 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
2836 /* NOTE : in case of ts streaming, player could not get the correct duration info *
2837 * skip the pull mode(file or ring buffering) setting. */
2838 if (dur_bytes > 0) {
2839 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
2840 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
2841 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
2847 _mm_player_streaming_set_queue2(player->streamer,
2851 (guint64)dur_bytes); /* no meaning at the moment */
2853 } else if (g_strrstr(factory_name, "parsebin")) {
2855 if (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
2856 GstIterator *iter = NULL;
2857 GValue item = {0, };
2858 GstElement *ch_element = NULL;
2859 GstElementFactory *ch_factory = NULL;
2861 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
2863 iter = gst_bin_iterate_recurse(child);
2865 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
2866 ch_element = g_value_get_object(&item);
2867 ch_factory = gst_element_get_factory(ch_element);
2869 if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) {
2870 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
2871 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
2873 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
2874 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
2875 (MMPLAYER_IS_DASH_STREAMING(player))) {
2876 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
2878 g_value_reset(&item);
2881 g_value_reset(&item);
2883 gst_iterator_free(iter);
2886 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
2887 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
2888 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2889 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
2891 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2892 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
2894 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2895 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2896 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort", G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2898 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2899 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2902 _mmplayer_gst_element_added((GstElement *)child, element, data);
2908 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2910 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
2915 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
2917 GstElement *uridecodebin3 = NULL;
2920 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2922 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
2923 if (!uridecodebin3) {
2924 LOGE("failed to create uridecodebin3");
2929 SECURE_LOGD("uri : %s", player->profile.uri);
2931 /* setting property to streaming source */
2932 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri, "message-forward", TRUE, NULL);
2934 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2935 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "source-setup", G_CALLBACK(__mmplayer_http_src_setup), (gpointer)player);
2937 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2938 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2940 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2941 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
2943 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2944 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
2946 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2947 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
2949 /* FIXME: need to be added for gapless playback
2950 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2951 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
2954 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2955 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
2957 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2958 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
2960 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2961 LOGW("[DASH] this is still experimental feature");
2964 return uridecodebin3;
2968 __mmplayer_gst_make_http_src(mmplayer_t *player)
2970 #define MAX_RETRY_COUNT 10
2971 GstElement *element = NULL;
2972 MMHandleType attrs = 0;
2973 gchar *user_agent, *cookies, **cookie_list;
2974 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2976 user_agent = cookies = NULL;
2980 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2982 /* get profile attribute */
2983 attrs = MMPLAYER_GET_ATTRS(player);
2985 LOGE("failed to get content attribute");
2989 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2991 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2993 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2998 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2999 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3001 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3002 http_timeout = player->ini.http_timeout;
3005 SECURE_LOGD("location : %s", player->profile.uri);
3006 SECURE_LOGD("cookies : %s", cookies);
3007 SECURE_LOGD("user_agent : %s", user_agent);
3008 LOGD("timeout : %d", http_timeout);
3010 /* setting property to streaming source */
3011 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3012 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3013 "retries", MAX_RETRY_COUNT, NULL);
3015 /* parsing cookies */
3016 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3017 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3018 g_strfreev(cookie_list);
3022 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3024 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3025 LOGW("[DASH] this is still experimental feature");
3032 __mmplayer_gst_make_file_src(mmplayer_t *player)
3034 GstElement *element = NULL;
3037 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3039 LOGD("using filesrc for 'file://' handler");
3040 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3041 LOGE("failed to get storage info");
3045 element = gst_element_factory_make("filesrc", "source");
3047 LOGE("failed to create filesrc");
3051 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3058 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3060 mmplayer_t *player = (mmplayer_t *)data;
3062 g_return_val_if_fail(player, FALSE);
3063 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3065 gst_message_ref(msg);
3067 g_mutex_lock(&player->bus_msg_q_lock);
3068 g_queue_push_tail(player->bus_msg_q, msg);
3069 g_mutex_unlock(&player->bus_msg_q_lock);
3071 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3072 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3073 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3077 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3079 mmplayer_t *player = (mmplayer_t *)(data);
3080 GstMessage *msg = NULL;
3084 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3086 player->pipeline->mainbin &&
3087 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3090 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3092 LOGE("cannot get BUS from the pipeline");
3096 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3098 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3099 while (!player->bus_msg_thread_exit) {
3100 g_mutex_lock(&player->bus_msg_q_lock);
3101 msg = g_queue_pop_head(player->bus_msg_q);
3102 g_mutex_unlock(&player->bus_msg_q_lock);
3104 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3107 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3108 /* handle the gst msg */
3109 __mmplayer_gst_bus_msg_callback(msg, player);
3110 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3111 gst_message_unref(msg);
3114 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3115 gst_object_unref(GST_OBJECT(bus));
3122 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3124 gint64 dur_nsec = 0;
3127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3129 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3130 return MM_ERROR_NONE;
3132 /* NOTE : duration cannot be zero except live streaming.
3133 * Since some element could have some timing problemn with quering duration, try again.
3135 if (player->duration == 0) {
3136 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3137 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3138 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3139 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3140 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3141 player->pending_seek.is_pending = true;
3142 player->pending_seek.pos = position;
3143 player->seek_state = MMPLAYER_SEEK_NONE;
3144 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3145 return MM_ERROR_PLAYER_NO_OP;
3147 player->seek_state = MMPLAYER_SEEK_NONE;
3148 return MM_ERROR_PLAYER_SEEK;
3151 player->duration = dur_nsec;
3154 if (player->duration > 0 && player->duration < position) {
3155 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3156 return MM_ERROR_INVALID_ARGUMENT;
3160 return MM_ERROR_NONE;
3164 __mmplayer_gst_check_seekable(mmplayer_t *player)
3166 GstQuery *query = NULL;
3167 gboolean seekable = FALSE;
3169 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3173 query = gst_query_new_seeking(GST_FORMAT_TIME);
3174 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3175 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3176 gst_query_unref(query);
3179 LOGW("non-seekable content");
3180 player->seek_state = MMPLAYER_SEEK_NONE;
3184 LOGW("failed to get seeking query");
3185 gst_query_unref(query); /* keep seeking operation */
3192 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3194 GstState element_state = GST_STATE_VOID_PENDING;
3195 GstState element_pending_state = GST_STATE_VOID_PENDING;
3196 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3200 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3201 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3203 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3206 ret = gst_element_set_state(element, state);
3207 if (ret == GST_STATE_CHANGE_FAILURE) {
3208 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3210 /* dump state of all element */
3211 _mmplayer_dump_pipeline_state(player);
3213 return MM_ERROR_PLAYER_INTERNAL;
3216 /* return here so state transition to be done in async mode */
3218 LOGD("async state transition. not waiting for state complete.");
3219 return MM_ERROR_NONE;
3222 /* wait for state transition */
3223 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3224 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3225 LOGE("failed to change [%s] element state to [%s] within %d sec",
3226 GST_ELEMENT_NAME(element),
3227 gst_element_state_get_name(state), timeout);
3229 LOGE(" [%s] state : %s pending : %s",
3230 GST_ELEMENT_NAME(element),
3231 gst_element_state_get_name(element_state),
3232 gst_element_state_get_name(element_pending_state));
3234 /* dump state of all element */
3235 _mmplayer_dump_pipeline_state(player);
3237 return MM_ERROR_PLAYER_INTERNAL;
3240 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3244 return MM_ERROR_NONE;
3248 _mmplayer_gst_start(mmplayer_t *player)
3250 int ret = MM_ERROR_NONE;
3251 gboolean async = FALSE;
3255 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3257 /* NOTE : if SetPosition was called before Start. do it now
3258 * streaming doesn't support it. so it should be always sync
3259 * !!create one more api to check if there is pending seek rather than checking variables
3261 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3262 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3263 ret = _mmplayer_gst_pause(player, FALSE);
3264 if (ret != MM_ERROR_NONE) {
3265 LOGE("failed to set state to PAUSED for pending seek");
3269 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3270 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3271 LOGW("failed to seek pending postion. starting from the begin of content");
3274 LOGD("current state before doing transition");
3275 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3276 MMPLAYER_PRINT_STATE(player);
3278 /* set pipeline state to PLAYING */
3279 ret = _mmplayer_gst_set_state(player,
3280 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3281 if (ret != MM_ERROR_NONE) {
3282 LOGE("failed to set state to PLAYING");
3286 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3288 /* generating debug info before returning error */
3289 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3297 _mmplayer_gst_stop(mmplayer_t *player)
3299 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3300 MMHandleType attrs = 0;
3301 gboolean rewind = FALSE;
3303 int ret = MM_ERROR_NONE;
3307 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3308 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3310 LOGD("current state before doing transition");
3311 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3312 MMPLAYER_PRINT_STATE(player);
3314 attrs = MMPLAYER_GET_ATTRS(player);
3316 LOGE("cannot get content attribute");
3317 return MM_ERROR_PLAYER_INTERNAL;
3320 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3321 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3323 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3324 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3327 if (player->es_player_push_mode)
3328 /* disable the async state transition because there could be no data in the pipeline */
3329 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3332 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3334 if (player->es_player_push_mode) {
3335 /* enable the async state transition as default operation */
3336 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3339 /* return if set_state has failed */
3340 if (ret != MM_ERROR_NONE) {
3341 LOGE("failed to set state.");
3347 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3348 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3349 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3350 LOGW("failed to rewind");
3351 ret = MM_ERROR_PLAYER_SEEK;
3356 player->sent_bos = FALSE;
3358 if (player->es_player_push_mode) //for cloudgame
3361 /* wait for seek to complete */
3362 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3363 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3364 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3366 LOGE("fail to stop player.");
3367 ret = MM_ERROR_PLAYER_INTERNAL;
3368 _mmplayer_dump_pipeline_state(player);
3371 /* generate dot file if enabled */
3372 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3380 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3382 int ret = MM_ERROR_NONE;
3386 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3387 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3389 LOGD("current state before doing transition");
3390 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3391 MMPLAYER_PRINT_STATE(player);
3393 /* set pipeline status to PAUSED */
3394 ret = _mmplayer_gst_set_state(player,
3395 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3400 if (ret != MM_ERROR_NONE) {
3401 GstMessage *msg = NULL;
3402 GTimer *timer = NULL;
3403 gdouble MAX_TIMEOUT_SEC = 3;
3405 LOGE("failed to set state to PAUSED");
3407 if (!player->bus_watcher) {
3408 LOGE("there is no bus msg thread. pipeline is shutting down.");
3412 if (player->msg_posted) {
3413 LOGE("error msg is already posted.");
3417 timer = g_timer_new();
3418 g_timer_start(timer);
3420 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3423 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3425 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3426 GError *error = NULL;
3428 /* parse error code */
3429 gst_message_parse_error(msg, &error, NULL);
3431 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3432 /* Note : the streaming error from the streaming source is handled
3433 * using __mmplayer_handle_streaming_error.
3435 __mmplayer_handle_streaming_error(player, msg);
3438 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3440 if (error->domain == GST_STREAM_ERROR)
3441 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3442 else if (error->domain == GST_RESOURCE_ERROR)
3443 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3444 else if (error->domain == GST_LIBRARY_ERROR)
3445 ret = __mmplayer_gst_handle_library_error(player, error->code);
3446 else if (error->domain == GST_CORE_ERROR)
3447 ret = __mmplayer_gst_handle_core_error(player, error->code);
3449 g_error_free(error);
3451 player->msg_posted = TRUE;
3453 gst_message_unref(msg);
3455 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3457 gst_object_unref(bus);
3458 g_timer_stop(timer);
3459 g_timer_destroy(timer);
3464 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3465 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3466 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3467 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3470 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3473 /* generate dot file before returning error */
3474 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3482 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3484 int ret = MM_ERROR_NONE;
3489 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3490 MM_ERROR_PLAYER_NOT_INITIALIZED);
3492 LOGD("current state before doing transition");
3493 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3494 MMPLAYER_PRINT_STATE(player);
3497 LOGD("do async state transition to PLAYING");
3499 /* set pipeline state to PLAYING */
3500 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3502 ret = _mmplayer_gst_set_state(player,
3503 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3504 if (ret != MM_ERROR_NONE) {
3505 LOGE("failed to set state to PLAYING");
3510 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3513 /* generate dot file */
3514 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3521 /* sending event to one of sinkelements */
3523 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3525 GstEvent *event2 = NULL;
3526 GList *sinks = NULL;
3527 gboolean res = FALSE;
3530 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3531 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3533 /* While adding subtitles in live feeds seek is getting called.
3534 Adding defensive check in framework layer.*/
3535 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3536 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3537 LOGE("Should not send seek event during live playback");
3542 if (player->play_subtitle)
3543 event2 = gst_event_copy((const GstEvent *)event);
3545 sinks = player->sink_elements;
3547 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3549 if (GST_IS_ELEMENT(sink)) {
3550 /* keep ref to the event */
3551 gst_event_ref(event);
3553 if ((res = gst_element_send_event(sink, event))) {
3554 LOGD("sending event[%s] to sink element [%s] success!",
3555 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3557 /* rtsp case, asyn_done is not called after seek during pause state */
3558 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3559 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3560 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3561 LOGD("RTSP seek completed, after pause state..");
3562 player->seek_state = MMPLAYER_SEEK_NONE;
3563 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3569 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3570 sinks = g_list_next(sinks);
3577 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3578 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3581 sinks = g_list_next(sinks);
3584 /* Note : Textbin is not linked to the video or audio bin.
3585 * It needs to send the event to the text sink seperatelly.
3587 if (player->play_subtitle && player->pipeline) {
3588 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3590 if (GST_IS_ELEMENT(text_sink)) {
3591 /* keep ref to the event */
3592 gst_event_ref(event2);
3594 if ((res = gst_element_send_event(text_sink, event2)))
3595 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3596 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3598 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3599 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3601 gst_event_unref(event2);
3605 gst_event_unref(event);
3613 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3614 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3615 gint64 cur, GstSeekType stop_type, gint64 stop)
3617 GstEvent *event = NULL;
3618 gboolean result = FALSE;
3622 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3624 if (player->pipeline && player->pipeline->textbin)
3625 __mmplayer_drop_subtitle(player, FALSE);
3627 event = gst_event_new_seek(rate, format, flags, cur_type,
3628 cur, stop_type, stop);
3630 result = _mmplayer_gst_send_event_to_sink(player, event);
3638 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3640 int ret = MM_ERROR_NONE;
3641 gint64 pos_nsec = 0;
3642 gboolean accurated = FALSE;
3643 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3646 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3647 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3649 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3650 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3653 ret = __mmplayer_gst_check_duration(player, position);
3654 if (ret != MM_ERROR_NONE) {
3655 LOGE("failed to check duration 0x%X", ret);
3656 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3659 if (!__mmplayer_gst_check_seekable(player))
3660 return MM_ERROR_PLAYER_NO_OP;
3662 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3663 position, player->playback_rate, player->duration);
3665 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3666 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3667 This causes problem is position calculation during normal pause resume scenarios also.
3668 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3669 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3670 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3671 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3672 LOGW("getting current position failed in seek");
3674 player->last_position = pos_nsec;
3675 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3678 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3679 LOGD("not completed seek");
3680 return MM_ERROR_PLAYER_DOING_SEEK;
3683 if (!internal_called)
3684 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3686 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3687 that's why set position through property. */
3688 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3689 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3690 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3691 (!player->videodec_linked) && (!player->audiodec_linked)) {
3693 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3694 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3696 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3697 player->seek_state = MMPLAYER_SEEK_NONE;
3698 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3700 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3702 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3704 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3706 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3707 GST_FORMAT_TIME, seek_flags,
3708 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3709 LOGE("failed to set position");
3714 /* NOTE : store last seeking point to overcome some bad operation
3715 * (returning zero when getting current position) of some elements
3717 player->last_position = position;
3719 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3720 if (player->playback_rate > 1.0)
3721 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3723 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3724 LOGD("buffering should be reset after seeking");
3725 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3726 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3730 return MM_ERROR_NONE;
3733 player->pending_seek.is_pending = true;
3734 player->pending_seek.pos = position;
3736 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3737 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3738 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3739 player->pending_seek.pos);
3741 return MM_ERROR_NONE;
3744 player->seek_state = MMPLAYER_SEEK_NONE;
3745 return MM_ERROR_PLAYER_SEEK;
3749 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3751 #define TRICKPLAY_OFFSET GST_MSECOND
3753 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3754 gint64 pos_nsec = 0;
3755 gboolean ret = TRUE;
3757 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3758 MM_ERROR_PLAYER_NOT_INITIALIZED);
3760 current_state = MMPLAYER_CURRENT_STATE(player);
3762 /* NOTE : query position except paused state to overcome some bad operation
3763 * please refer to below comments in details
3765 if (current_state != MM_PLAYER_STATE_PAUSED)
3766 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3768 /* NOTE : get last point to overcome some bad operation of some elements
3769 *(returning zero when getting current position in paused state
3770 * and when failed to get postion during seeking
3772 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3773 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3775 if (player->playback_rate < 0.0)
3776 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3778 pos_nsec = player->last_position;
3781 pos_nsec = player->last_position;
3783 player->last_position = pos_nsec;
3785 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3788 if (player->duration > 0 && pos_nsec > player->duration)
3789 pos_nsec = player->duration;
3791 player->last_position = pos_nsec;
3794 *position = pos_nsec;
3796 return MM_ERROR_NONE;
3800 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3802 #define STREAMING_IS_FINISHED 0
3803 #define BUFFERING_MAX_PER 100
3804 #define DEFAULT_PER_VALUE -1
3805 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3807 mmplayer_gst_element_t *mainbin = NULL;
3808 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3809 gint64 buffered_total = 0;
3810 gint64 position = 0;
3811 gint buffered_sec = -1;
3812 GstBufferingMode mode = GST_BUFFERING_STREAM;
3813 gint64 content_size_time = player->duration;
3814 guint64 content_size_bytes = player->http_content_size;
3816 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3818 player->pipeline->mainbin,
3819 MM_ERROR_PLAYER_NOT_INITIALIZED);
3821 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3826 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3827 /* and rtsp is not ready yet. */
3828 LOGW("it's only used for http streaming case");
3829 return MM_ERROR_PLAYER_NO_OP;
3832 if (content_size_time <= 0 || content_size_bytes <= 0) {
3833 LOGW("there is no content size");
3834 return MM_ERROR_NONE;
3837 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3838 LOGW("fail to get current position");
3839 return MM_ERROR_NONE;
3842 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3843 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3845 mainbin = player->pipeline->mainbin;
3846 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3848 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3849 GstQuery *query = NULL;
3850 gint byte_in_rate = 0, byte_out_rate = 0;
3851 gint64 estimated_total = 0;
3853 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3854 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3855 LOGW("fail to get buffering query from queue2");
3857 gst_query_unref(query);
3858 return MM_ERROR_NONE;
3861 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3862 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3864 if (mode == GST_BUFFERING_STREAM) {
3865 /* using only queue in case of push mode(ts / mp3) */
3866 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3867 GST_FORMAT_BYTES, &buffered_total)) {
3868 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3869 end_per = 100 * buffered_total / content_size_bytes;
3872 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3874 guint num_of_ranges = 0;
3875 gint64 start_byte = 0, stop_byte = 0;
3877 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3878 if (estimated_total != STREAMING_IS_FINISHED) {
3879 /* buffered size info from queue2 */
3880 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3881 for (idx = 0; idx < num_of_ranges; idx++) {
3882 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3883 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3885 buffered_total += (stop_byte - start_byte);
3888 end_per = BUFFERING_MAX_PER;
3891 gst_query_unref(query);
3894 if (end_per == DEFAULT_PER_VALUE) {
3895 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3897 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3899 /* buffered size info from multiqueue */
3900 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3901 guint curr_size_bytes = 0;
3902 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3903 "curr-size-bytes", &curr_size_bytes, NULL);
3904 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3905 buffered_total += curr_size_bytes;
3908 if (avg_byterate > 0)
3909 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3910 else if (player->total_maximum_bitrate > 0)
3911 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3912 else if (player->total_bitrate > 0)
3913 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3915 if (buffered_sec >= 0)
3916 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3920 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3921 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3923 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3924 buffered_total, buffered_sec, *start_pos, *end_pos);
3926 return MM_ERROR_NONE;
3930 _mmplayer_gst_create_source(mmplayer_t *player)
3932 GstElement *element = NULL;
3935 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3936 player->pipeline->mainbin, NULL);
3938 /* setup source for gapless play */
3939 switch (player->profile.uri_type) {
3941 case MM_PLAYER_URI_TYPE_FILE:
3942 element = __mmplayer_gst_make_file_src(player);
3944 case MM_PLAYER_URI_TYPE_URL_HTTP:
3945 element = __mmplayer_gst_make_http_src(player);
3948 LOGE("not support uri type %d", player->profile.uri_type);
3953 LOGE("failed to create source element");
3962 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3965 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3966 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3968 SECURE_LOGD("uri : %s", player->profile.uri);
3970 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3972 if ((player->v_stream_caps) &&
3973 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3974 return MM_ERROR_PLAYER_INTERNAL;
3976 if ((player->a_stream_caps) &&
3977 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3978 return MM_ERROR_PLAYER_INTERNAL;
3980 if ((player->s_stream_caps) &&
3981 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3982 return MM_ERROR_PLAYER_INTERNAL;
3985 return MM_ERROR_NONE;
3989 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3991 mmplayer_gst_element_t *mainbin = NULL;
3992 GstElement *src_elem = NULL;
3993 GstElement *autoplug_elem = NULL;
3994 GList *element_bucket = NULL;
3995 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3999 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4001 mainbin = player->pipeline->mainbin;
4003 LOGD("uri type %d", player->profile.uri_type);
4005 /* create source element */
4006 switch (player->profile.uri_type) {
4007 case MM_PLAYER_URI_TYPE_URL_RTSP:
4008 src_elem = __mmplayer_gst_make_rtsp_src(player);
4010 case MM_PLAYER_URI_TYPE_URL_HTTP:
4011 if (player->ini.use_uridecodebin3) { /* or MMPLAYER_USE_URIDECODEBIN3(player) */
4012 LOGD("uridecodebin include src element.");
4015 src_elem = __mmplayer_gst_make_http_src(player);
4017 case MM_PLAYER_URI_TYPE_FILE:
4018 src_elem = __mmplayer_gst_make_file_src(player);
4020 case MM_PLAYER_URI_TYPE_SS:
4022 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4023 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4025 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4029 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4030 LOGD("get timeout from ini");
4031 http_timeout = player->ini.http_timeout;
4034 /* setting property to streaming source */
4035 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4038 case MM_PLAYER_URI_TYPE_MEM:
4040 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4042 src_elem = gst_element_factory_make("appsrc", "mem-source");
4044 LOGE("failed to create appsrc element");
4048 g_object_set(src_elem, "stream-type", stream_type,
4049 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4051 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4052 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4053 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4054 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4058 LOGE("not support uri type");
4063 LOGE("failed to create source element");
4064 return MM_ERROR_PLAYER_INTERNAL;
4067 /* take source element */
4068 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4070 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4071 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4072 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4074 ADD_DECODEBIN: /* create next element for auto-plugging */
4075 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4076 if (!src_elem) { /* make uridecodebin3 which include src element */
4077 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4078 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4079 if (!autoplug_elem) {
4080 LOGE("failed to create uridecodebin3 element");
4084 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4085 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4086 if (!autoplug_elem) {
4087 LOGE("failed to create typefind element");
4090 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4091 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4093 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4094 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4095 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4096 if (!autoplug_elem) {
4097 LOGE("failed to create decodebin");
4101 /* default size of mq in decodebin is 2M
4102 * but it can cause blocking issue during seeking depends on content. */
4103 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4106 if (autoplug_elem) {
4107 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4108 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4109 mainbin[autoplug_elem_id].gst = autoplug_elem;
4111 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4114 /* add elements to pipeline */
4115 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4116 LOGE("failed to add elements to pipeline");
4120 /* linking elements in the bucket by added order. */
4121 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4122 LOGE("failed to link some elements");
4126 /* FIXME: need to check whether this is required or not. */
4127 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4128 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4129 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4130 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4131 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4133 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4134 LOGE("failed to create fakesink");
4137 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4139 /* take ownership of fakesink. we are reusing it */
4140 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4142 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4143 LOGE("failed to add fakesink to bin");
4144 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4149 g_list_free(element_bucket);
4152 return MM_ERROR_NONE;
4155 g_list_free(element_bucket);
4157 if (mainbin[MMPLAYER_M_SRC].gst)
4158 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4160 if (mainbin[autoplug_elem_id].gst)
4161 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4163 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4164 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4166 mainbin[MMPLAYER_M_SRC].gst = NULL;
4167 mainbin[autoplug_elem_id].gst = NULL;
4168 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4170 return MM_ERROR_PLAYER_INTERNAL;
4174 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4177 mmplayer_gst_element_t *mainbin = NULL;
4180 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4181 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4183 mainbin = player->pipeline->mainbin;
4185 /* connect bus callback */
4186 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4188 LOGE("cannot get bus from pipeline");
4189 return MM_ERROR_PLAYER_INTERNAL;
4192 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4193 player->context.thread_default = g_main_context_get_thread_default();
4194 if (player->context.thread_default == NULL) {
4195 player->context.thread_default = g_main_context_default();
4196 LOGD("thread-default context is the global default context");
4198 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4200 /* set sync handler to get tag synchronously */
4201 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4202 gst_object_unref(GST_OBJECT(bus));
4204 /* create gst bus_msb_cb thread */
4205 g_mutex_init(&player->bus_msg_thread_mutex);
4206 g_cond_init(&player->bus_msg_thread_cond);
4207 player->bus_msg_thread_exit = FALSE;
4208 player->bus_msg_thread =
4209 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4210 if (!player->bus_msg_thread) {
4211 LOGE("failed to create gst BUS msg thread");
4212 g_mutex_clear(&player->bus_msg_thread_mutex);
4213 g_cond_clear(&player->bus_msg_thread_cond);
4214 return MM_ERROR_PLAYER_INTERNAL;
4218 return MM_ERROR_NONE;
4222 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4224 mmplayer_gst_element_t *mainbin = NULL;
4225 MMMessageParamType msg_param = {0,};
4226 GstElement *element = NULL;
4227 MMHandleType attrs = 0;
4229 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4233 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4234 LOGE("player is not initialized");
4238 mainbin = player->pipeline->mainbin;
4239 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4241 attrs = MMPLAYER_GET_ATTRS(player);
4243 LOGE("fail to get attributes");
4247 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4249 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4250 LOGE("failed to parse profile");
4251 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4255 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4256 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4257 LOGE("dash or hls is not supportable");
4258 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4262 element = _mmplayer_gst_create_source(player);
4264 LOGE("no source element was created");
4268 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4269 LOGE("failed to add source element to pipeline");
4270 gst_object_unref(GST_OBJECT(element));
4275 /* take source element */
4276 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4277 mainbin[MMPLAYER_M_SRC].gst = element;
4281 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4282 if (player->streamer == NULL) {
4283 player->streamer = _mm_player_streaming_create();
4284 _mm_player_streaming_initialize(player->streamer, TRUE);
4287 elem_idx = MMPLAYER_M_TYPEFIND;
4288 element = gst_element_factory_make("typefind", "typefinder");
4289 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4290 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4292 elem_idx = MMPLAYER_M_AUTOPLUG;
4293 element = _mmplayer_gst_make_decodebin(player);
4296 /* check autoplug element is OK */
4298 LOGE("can not create element(%d)", elem_idx);
4302 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4303 LOGE("failed to add sinkbin to pipeline");
4304 gst_object_unref(GST_OBJECT(element));
4309 mainbin[elem_idx].id = elem_idx;
4310 mainbin[elem_idx].gst = element;
4312 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4313 LOGE("Failed to link src - autoplug(or typefind)");
4317 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4318 LOGE("Failed to change state of src element");
4322 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4323 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4324 LOGE("Failed to change state of decodebin");
4328 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4329 LOGE("Failed to change state of src element");
4334 player->gapless.stream_changed = TRUE;
4335 player->gapless.running = TRUE;
4341 _mmplayer_set_reconfigure_state(player, FALSE);
4342 if (!player->msg_posted) {
4343 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4344 player->msg_posted = TRUE;