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 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
89 /* check whether the error is posted from not-activated track or not */
91 gint active_pad_index = 0;
93 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
95 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
96 LOGD("current active pad index -%d", active_pad_index);
98 if (src_element_name) {
101 if (player->audio_decoders) {
102 GList *adec = player->audio_decoders;
103 for (; adec ; adec = g_list_next(adec)) {
104 gchar *name = adec->data;
106 LOGD("found audio decoder name = %s", name);
107 if (g_strrstr(name, src_element_name)) {
114 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
117 if (active_pad_index != msg_src_pos) {
118 LOGD("skip error because error is posted from no activated track");
126 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
128 /* Demuxer can't parse one track because it's corrupted.
129 * So, the decoder for it is not linked.
130 * But, it has one playable track.
132 if (g_strrstr(klass, "Demux")) {
133 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
134 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
135 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
136 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
138 if (player->pipeline->audiobin) { // PCM
139 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
141 LOGD("not found any available codec. Player should be destroyed.");
142 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
147 return MM_ERROR_PLAYER_INVALID_STREAM;
151 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
153 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
154 LOGE("Not supported subtitle.");
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
157 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
161 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
163 /* Decoder Custom Message */
164 if (!strstr(error->message, "ongoing"))
165 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
167 if (strncasecmp(klass, "audio", 5)) {
168 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
169 LOGD("Video can keep playing.");
170 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
172 } else if (strncasecmp(klass, "video", 5)) {
173 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
174 LOGD("Audio can keep playing.");
175 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
179 LOGD("not found any available codec. Player should be destroyed.");
180 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
184 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
186 if (strstr(error->message, "rights expired"))
187 return MM_ERROR_PLAYER_DRM_EXPIRED;
188 else if (strstr(error->message, "no rights"))
189 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
190 else if (strstr(error->message, "has future rights"))
191 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
192 else if (strstr(error->message, "opl violation"))
193 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
195 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
198 /* NOTE : decide gstreamer state whether there is some playable track or not. */
200 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
202 gchar *src_element_name = NULL;
203 GstElement *src_element = NULL;
204 GstElementFactory *factory = NULL;
205 const gchar *klass = NULL;
209 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
211 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
212 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
214 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
216 src_element = GST_ELEMENT_CAST(message->src);
218 return MM_ERROR_PLAYER_INTERNAL;
220 src_element_name = GST_ELEMENT_NAME(src_element);
221 if (!src_element_name)
222 return MM_ERROR_PLAYER_INTERNAL;
224 factory = gst_element_get_factory(src_element);
226 return MM_ERROR_PLAYER_INTERNAL;
228 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
230 return MM_ERROR_PLAYER_INTERNAL;
232 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
233 error->code, error->message, src_element_name, klass);
235 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
236 return MM_ERROR_NONE;
238 switch (error->code) {
239 case GST_STREAM_ERROR_DECODE:
240 return __mmplayer_gst_transform_error_decode(player, klass);
241 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
242 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
243 case GST_STREAM_ERROR_WRONG_TYPE:
244 return __mmplayer_gst_transform_error_type(player, src_element);
245 case GST_STREAM_ERROR_FAILED:
246 return __mmplayer_gst_transform_error_failed(player, klass, error);
247 case GST_STREAM_ERROR_DECRYPT:
248 case GST_STREAM_ERROR_DECRYPT_NOKEY:
249 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
250 return __mmplayer_gst_transform_error_decrypt(player, error);
257 return MM_ERROR_PLAYER_INVALID_STREAM;
261 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
263 gint trans_err = MM_ERROR_NONE;
267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
270 case GST_CORE_ERROR_MISSING_PLUGIN:
271 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
272 case GST_CORE_ERROR_STATE_CHANGE:
273 case GST_CORE_ERROR_SEEK:
274 case GST_CORE_ERROR_NOT_IMPLEMENTED:
275 case GST_CORE_ERROR_FAILED:
276 case GST_CORE_ERROR_TOO_LAZY:
277 case GST_CORE_ERROR_PAD:
278 case GST_CORE_ERROR_THREAD:
279 case GST_CORE_ERROR_NEGOTIATION:
280 case GST_CORE_ERROR_EVENT:
281 case GST_CORE_ERROR_CAPS:
282 case GST_CORE_ERROR_TAG:
283 case GST_CORE_ERROR_CLOCK:
284 case GST_CORE_ERROR_DISABLED:
286 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
296 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
298 gint trans_err = MM_ERROR_NONE;
302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
305 case GST_LIBRARY_ERROR_FAILED:
306 case GST_LIBRARY_ERROR_TOO_LAZY:
307 case GST_LIBRARY_ERROR_INIT:
308 case GST_LIBRARY_ERROR_SHUTDOWN:
309 case GST_LIBRARY_ERROR_SETTINGS:
310 case GST_LIBRARY_ERROR_ENCODE:
312 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
322 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
324 gint trans_err = MM_ERROR_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
331 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
332 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
334 case GST_RESOURCE_ERROR_NOT_FOUND:
335 case GST_RESOURCE_ERROR_OPEN_READ:
336 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
337 || MMPLAYER_IS_RTSP_STREAMING(player)) {
338 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
341 case GST_RESOURCE_ERROR_READ:
342 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
343 || MMPLAYER_IS_RTSP_STREAMING(player)) {
344 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
346 } else if (message != NULL && message->src != NULL) {
347 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
348 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
350 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
351 path_type = MMPLAYER_PATH_VOD;
352 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
353 path_type = MMPLAYER_PATH_TEXT;
355 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
356 /* check storage state */
357 storage_get_state(player->storage_info[path_type].id, &storage_state);
358 player->storage_info[path_type].state = storage_state;
359 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
362 case GST_RESOURCE_ERROR_WRITE:
363 case GST_RESOURCE_ERROR_FAILED:
364 case GST_RESOURCE_ERROR_SEEK:
365 case GST_RESOURCE_ERROR_TOO_LAZY:
366 case GST_RESOURCE_ERROR_BUSY:
367 case GST_RESOURCE_ERROR_OPEN_WRITE:
368 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
369 case GST_RESOURCE_ERROR_CLOSE:
370 case GST_RESOURCE_ERROR_SYNC:
371 case GST_RESOURCE_ERROR_SETTINGS:
373 trans_err = MM_ERROR_PLAYER_INTERNAL;
383 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
385 gint trans_err = MM_ERROR_NONE;
389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
390 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
391 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
393 switch (error->code) {
394 case GST_STREAM_ERROR_FAILED:
395 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
396 case GST_STREAM_ERROR_DECODE:
397 case GST_STREAM_ERROR_WRONG_TYPE:
398 case GST_STREAM_ERROR_DECRYPT:
399 case GST_STREAM_ERROR_DECRYPT_NOKEY:
400 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
401 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
404 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
405 case GST_STREAM_ERROR_TOO_LAZY:
406 case GST_STREAM_ERROR_ENCODE:
407 case GST_STREAM_ERROR_DEMUX:
408 case GST_STREAM_ERROR_MUX:
409 case GST_STREAM_ERROR_FORMAT:
411 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
421 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
423 MMMessageParamType msg_param;
424 gchar *msg_src_element;
428 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
429 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
431 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
433 memset(&msg_param, 0, sizeof(MMMessageParamType));
435 if (error->domain == GST_CORE_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
437 } else if (error->domain == GST_LIBRARY_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
439 } else if (error->domain == GST_RESOURCE_ERROR) {
440 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
441 } else if (error->domain == GST_STREAM_ERROR) {
442 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
444 LOGW("This error domain is not defined.");
446 /* we treat system error as an internal error */
447 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
451 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
453 msg_param.data = (void *)error->message;
455 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
456 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
460 if (msg_param.code == MM_ERROR_NONE)
463 /* skip error to avoid duplicated posting */
464 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
465 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
466 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
467 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
469 /* The error will be handled by mused.
470 * @ref _mmplayer_manage_external_storage_state() */
472 LOGW("storage is removed, skip error post");
476 /* post error to application */
477 if (!player->msg_posted) {
478 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
479 /* don't post more if one was sent already */
480 player->msg_posted = TRUE;
482 LOGD("skip error post because it's sent already.");
491 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
494 MMMessageParamType msg_param;
495 gchar *msg_src_element = NULL;
496 GstStructure *s = NULL;
498 gchar *error_string = NULL;
502 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
503 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
505 s = gst_structure_copy(gst_message_get_structure(message));
508 if (!gst_structure_get_uint(s, "error_id", &error_id))
509 error_id = MMPLAYER_STREAMING_ERROR_NONE;
512 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
515 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
518 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
521 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
524 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
527 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
530 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
533 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
536 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
539 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
542 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
545 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
548 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
551 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
554 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
557 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
560 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
563 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
566 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
569 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
572 case MMPLAYER_STREAMING_ERROR_GONE:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
575 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
578 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
581 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
584 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
587 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
590 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
593 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
596 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
599 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
602 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
605 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
608 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
611 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
614 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
617 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
620 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
623 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
626 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
629 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
632 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
635 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
636 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
638 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
639 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
641 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
642 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
644 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
645 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
649 gst_structure_free(s);
650 return MM_ERROR_PLAYER_STREAMING_FAIL;
654 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
656 msg_param.data = (void *)error_string;
659 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
661 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]",
662 msg_src_element, msg_param.code, (char *)msg_param.data);
665 /* post error to application */
666 if (!player->msg_posted) {
667 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
669 /* don't post more if one was sent already */
670 player->msg_posted = TRUE;
672 LOGD("skip error post because it's sent already.");
675 gst_structure_free(s);
676 MMPLAYER_FREEIF(error_string);
684 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
686 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
687 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
688 gst_tag_list_get_string(tags, "stitching_software",
689 &metadata->stitching_software);
690 gst_tag_list_get_string(tags, "projection_type",
691 &metadata->projection_type_string);
692 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
693 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
694 gst_tag_list_get_int(tags, "init_view_heading",
695 &metadata->init_view_heading);
696 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
697 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
698 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
699 gst_tag_list_get_int(tags, "full_pano_width_pixels",
700 &metadata->full_pano_width_pixels);
701 gst_tag_list_get_int(tags, "full_pano_height_pixels",
702 &metadata->full_pano_height_pixels);
703 gst_tag_list_get_int(tags, "cropped_area_image_width",
704 &metadata->cropped_area_image_width);
705 gst_tag_list_get_int(tags, "cropped_area_image_height",
706 &metadata->cropped_area_image_height);
707 gst_tag_list_get_int(tags, "cropped_area_left",
708 &metadata->cropped_area_left);
709 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
710 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
711 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
712 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
716 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
719 /* macro for better code readability */
720 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
722 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
723 if (string != NULL) { \
724 SECURE_LOGD("update tag string : %s", string); \
725 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
726 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
727 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
728 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
729 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
730 MMPLAYER_FREEIF(new_string); \
732 mm_attrs_set_string_by_name(attribute, playertag, string); \
734 MMPLAYER_FREEIF(string); \
739 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
741 GstSample *sample = NULL;\
742 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
743 GstMapInfo info = GST_MAP_INFO_INIT;\
744 buffer = gst_sample_get_buffer(sample);\
745 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
746 LOGD("failed to get image data from tag");\
747 gst_sample_unref(sample);\
750 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
751 MMPLAYER_FREEIF(player->album_art);\
752 player->album_art = (gchar *)g_malloc(info.size);\
753 if (player->album_art) {\
754 memcpy(player->album_art, info.data, info.size);\
755 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
756 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
757 msg_param.data = (void *)player->album_art;\
758 msg_param.size = info.size;\
759 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
760 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
763 gst_buffer_unmap(buffer, &info);\
764 gst_sample_unref(sample);\
768 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
770 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
773 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
774 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
775 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
776 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
777 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
779 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
780 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
781 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
782 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
783 player->bitrate[track_type] = v_uint; \
784 player->total_bitrate = 0; \
785 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
786 player->total_bitrate += player->bitrate[i]; \
787 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
788 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
789 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
790 player->maximum_bitrate[track_type] = v_uint; \
791 player->total_maximum_bitrate = 0; \
792 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
793 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
794 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
795 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
797 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
804 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
806 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
808 string = g_strdup_printf("%d", g_date_get_year(date));\
809 mm_attrs_set_string_by_name(attribute, playertag, string);\
810 SECURE_LOGD("metainfo year : %s", string);\
811 MMPLAYER_FREEIF(string);\
817 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
820 if (datetime != NULL) {\
821 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
822 mm_attrs_set_string_by_name(attribute, playertag, string);\
823 SECURE_LOGD("metainfo year : %s", string);\
824 MMPLAYER_FREEIF(string);\
825 gst_date_time_unref(datetime);\
830 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
832 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
834 /* FIXIT : don't know how to store date */\
841 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
843 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
845 /* FIXIT : don't know how to store date */\
853 GstTagList *tag_list = NULL;
855 MMHandleType attrs = 0;
860 GstDateTime *datetime = NULL;
862 GstBuffer *buffer = NULL;
864 MMMessageParamType msg_param = {0, };
866 /* currently not used. but those are needed for above macro */
867 //guint64 v_uint64 = 0;
868 //gdouble v_double = 0;
870 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
872 attrs = MMPLAYER_GET_ATTRS(player);
874 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
876 /* get tag list from gst message */
877 gst_message_parse_tag(msg, &tag_list);
879 /* store tags to player attributes */
880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
882 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
887 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
888 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
892 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
898 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
901 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
904 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
905 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
907 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
909 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
910 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
911 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
912 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
913 MMPLAYER_UPDATE_TAG_LOCK(player);
914 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
915 MMPLAYER_UPDATE_TAG_UNLOCK(player);
916 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
917 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
918 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
920 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
921 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
922 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
923 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
924 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
925 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
927 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
930 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
931 if (player->video360_metadata.is_spherical == -1) {
932 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
933 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
934 player->video360_metadata.is_spherical);
935 if (player->video360_metadata.is_spherical == 1) {
936 LOGD("This is spherical content for 360 playback.");
937 player->is_content_spherical = TRUE;
939 LOGD("This is not spherical content");
940 player->is_content_spherical = FALSE;
943 if (player->video360_metadata.projection_type_string) {
944 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
945 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
947 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
948 player->is_content_spherical = player->is_video360_enabled = FALSE;
952 if (player->video360_metadata.stereo_mode_string) {
953 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
954 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
955 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
956 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
957 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
958 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
960 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
961 player->is_content_spherical = player->is_video360_enabled = FALSE;
967 if (mm_attrs_commit_all(attrs))
968 LOGE("failed to commit.");
970 gst_tag_list_unref(tag_list);
975 /* if retval is FALSE, it will be dropped for perfomance. */
977 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
979 gboolean retval = FALSE;
981 if (!(player->pipeline && player->pipeline->mainbin)) {
982 LOGE("player pipeline handle is null");
986 switch (GST_MESSAGE_TYPE(message)) {
987 case GST_MESSAGE_TAG:
988 case GST_MESSAGE_EOS:
989 case GST_MESSAGE_ERROR:
990 case GST_MESSAGE_WARNING:
991 case GST_MESSAGE_CLOCK_LOST:
992 case GST_MESSAGE_NEW_CLOCK:
993 case GST_MESSAGE_ELEMENT:
994 case GST_MESSAGE_DURATION_CHANGED:
995 case GST_MESSAGE_ASYNC_START:
996 case GST_MESSAGE_STREAM_COLLECTION:
999 case GST_MESSAGE_ASYNC_DONE:
1000 case GST_MESSAGE_STATE_CHANGED:
1001 /* we only handle messages from pipeline */
1002 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
1005 case GST_MESSAGE_BUFFERING:
1007 gint buffer_percent = 0;
1010 gst_message_parse_buffering(message, &buffer_percent);
1011 if (buffer_percent != MAX_BUFFER_PERCENT) {
1012 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1016 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1017 LOGW("can't get cmd lock, send msg to bus");
1021 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1022 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1023 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1026 MMPLAYER_CMD_UNLOCK(player);
1030 case GST_MESSAGE_STREAMS_SELECTED:
1032 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1033 break; /* drop msg */
1035 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1036 player->no_more_pad = TRUE;
1037 _mmplayer_pipeline_complete(NULL, player);
1049 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1051 guint64 data_size = 0;
1052 gint64 pos_nsec = 0;
1054 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1056 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1058 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1059 data_size = player->http_content_size;
1062 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1063 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1069 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1071 int ret = MM_ERROR_NONE;
1072 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1073 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1074 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1075 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1077 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1078 LOGW("do nothing for buffering msg");
1079 ret = MM_ERROR_PLAYER_INVALID_STATE;
1083 prev_state = MMPLAYER_PREV_STATE(player);
1084 current_state = MMPLAYER_CURRENT_STATE(player);
1085 target_state = MMPLAYER_TARGET_STATE(player);
1086 pending_state = MMPLAYER_PENDING_STATE(player);
1088 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1089 MMPLAYER_STATE_GET_NAME(prev_state),
1090 MMPLAYER_STATE_GET_NAME(current_state),
1091 MMPLAYER_STATE_GET_NAME(pending_state),
1092 MMPLAYER_STATE_GET_NAME(target_state),
1093 player->streamer->buffering_state);
1095 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1096 /* NOTE : if buffering has done, player has to go to target state. */
1097 switch (target_state) {
1098 case MM_PLAYER_STATE_PAUSED:
1100 switch (pending_state) {
1101 case MM_PLAYER_STATE_PLAYING:
1102 _mmplayer_gst_pause(player, TRUE);
1105 case MM_PLAYER_STATE_PAUSED:
1106 LOGD("player is already going to paused state, there is nothing to do.");
1109 case MM_PLAYER_STATE_NONE:
1110 case MM_PLAYER_STATE_NULL:
1111 case MM_PLAYER_STATE_READY:
1113 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1119 case MM_PLAYER_STATE_PLAYING:
1121 switch (pending_state) {
1122 case MM_PLAYER_STATE_NONE:
1124 if (current_state != MM_PLAYER_STATE_PLAYING)
1125 _mmplayer_gst_resume(player, TRUE);
1129 case MM_PLAYER_STATE_PAUSED:
1130 /* NOTE: It should be worked as asynchronously.
1131 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1133 if (current_state == MM_PLAYER_STATE_PLAYING) {
1134 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1135 * The current state should be changed to paused purposely to prevent state conflict.
1137 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1139 _mmplayer_gst_resume(player, TRUE);
1142 case MM_PLAYER_STATE_PLAYING:
1143 LOGD("player is already going to playing state, there is nothing to do.");
1146 case MM_PLAYER_STATE_NULL:
1147 case MM_PLAYER_STATE_READY:
1149 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1155 case MM_PLAYER_STATE_NULL:
1156 case MM_PLAYER_STATE_READY:
1157 case MM_PLAYER_STATE_NONE:
1159 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1163 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1164 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1166 switch (pending_state) {
1167 case MM_PLAYER_STATE_NONE:
1169 if (current_state != MM_PLAYER_STATE_PAUSED) {
1170 /* rtsp streaming pause makes rtsp server stop sending data. */
1171 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1172 LOGD("set pause state during buffering");
1173 _mmplayer_gst_pause(player, TRUE);
1179 case MM_PLAYER_STATE_PLAYING:
1180 /* rtsp streaming pause makes rtsp server stop sending data. */
1181 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1182 _mmplayer_gst_pause(player, TRUE);
1185 case MM_PLAYER_STATE_PAUSED:
1188 case MM_PLAYER_STATE_NULL:
1189 case MM_PLAYER_STATE_READY:
1191 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1200 static stream_variant_t *
1201 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1203 stream_variant_t *var_info = NULL;
1204 g_return_val_if_fail(self != NULL, NULL);
1206 var_info = g_new0(stream_variant_t, 1);
1207 if (!var_info) return NULL;
1208 var_info->bandwidth = self->bandwidth;
1209 var_info->width = self->width;
1210 var_info->height = self->height;
1215 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1222 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1224 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1225 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1226 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1228 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1229 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1230 player->http_content_size = (bytes > 0) ? bytes : 0;
1233 /* handling audio clip which has vbr. means duration is keep changing */
1234 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1243 __mmplayer_eos_timer_cb(gpointer u_data)
1245 mmplayer_t *player = NULL;
1246 MMHandleType attrs = 0;
1249 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1251 player = (mmplayer_t *)u_data;
1252 attrs = MMPLAYER_GET_ATTRS(player);
1254 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1258 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1259 if (ret_value != MM_ERROR_NONE)
1260 LOGE("seeking to 0 failed in repeat play");
1263 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1266 /* we are returning FALSE as we need only one posting */
1271 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1273 MMPLAYER_RETURN_IF_FAIL(player);
1275 /* post now if delay is zero */
1276 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1277 LOGD("eos delay is zero. posting EOS now");
1278 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1280 if (player->audio_decoded_cb)
1281 _mmplayer_cancel_eos_timer(player);
1286 /* cancel if existing */
1287 _mmplayer_cancel_eos_timer(player);
1289 /* init new timeout */
1290 /* NOTE : consider give high priority to this timer */
1291 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1293 player->eos_timer = g_timeout_add(delay_in_ms,
1294 __mmplayer_eos_timer_cb, player);
1296 player->context.global_default = g_main_context_default();
1297 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1299 /* check timer is valid. if not, send EOS now */
1300 if (player->eos_timer == 0) {
1301 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1302 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1307 __mmplayer_gst_pending_seek(mmplayer_t *player)
1309 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1310 int ret = MM_ERROR_NONE;
1314 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1316 if (!player->pending_seek.is_pending) {
1317 LOGD("pending seek is not reserved. nothing to do.");
1321 /* check player state if player could pending seek or not. */
1322 current_state = MMPLAYER_CURRENT_STATE(player);
1324 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1325 LOGW("try to pending seek in %s state, try next time. ",
1326 MMPLAYER_STATE_GET_NAME(current_state));
1330 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1332 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1333 if (ret != MM_ERROR_NONE)
1334 LOGE("failed to seek pending postion. just keep staying current position.");
1336 player->pending_seek.is_pending = false;
1344 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1346 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1348 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1350 audiobin = player->pipeline->audiobin; /* can be null */
1351 videobin = player->pipeline->videobin; /* can be null */
1352 textbin = player->pipeline->textbin; /* can be null */
1354 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1356 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1357 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1359 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1360 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1362 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1363 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1369 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1371 mmplayer_gst_element_t *textbin;
1374 MMPLAYER_RETURN_IF_FAIL(player &&
1376 player->pipeline->textbin);
1378 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1380 textbin = player->pipeline->textbin;
1383 LOGD("Drop subtitle text after getting EOS");
1385 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1386 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1388 player->is_subtitle_force_drop = TRUE;
1390 if (player->is_subtitle_force_drop == TRUE) {
1391 LOGD("Enable subtitle data path without drop");
1393 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1394 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1396 LOGD("non-connected with external display");
1398 player->is_subtitle_force_drop = FALSE;
1404 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1406 MMHandleType attrs = 0;
1411 /* NOTE : EOS event is comming multiple time. watch out it */
1412 /* check state. we only process EOS when pipeline state goes to PLAYING */
1413 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1414 LOGD("EOS received on non-playing state. ignoring it");
1418 if (player->pipeline && player->pipeline->textbin)
1419 __mmplayer_drop_subtitle(player, TRUE);
1421 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1422 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1424 /* rewind if repeat count is greater then zero */
1425 /* get play count */
1426 attrs = MMPLAYER_GET_ATTRS(player);
1428 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1430 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1432 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1433 if (player->playback_rate < 0.0) {
1434 player->resumed_by_rewind = TRUE;
1435 _mmplayer_set_mute((MMHandleType)player, false);
1436 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1439 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1442 player->sent_bos = FALSE;
1444 LOGD("do not post eos msg for repeating");
1449 if (player->pipeline)
1450 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1452 /* post eos message to application */
1453 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1455 /* reset last position */
1456 player->last_position = 0;
1463 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1465 GError *error = NULL;
1466 gchar *debug = NULL;
1470 /* generating debug info before returning error */
1471 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1473 /* get error code */
1474 gst_message_parse_error(msg, &error, &debug);
1476 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1477 /* Note : the streaming error from the streaming source is handled
1478 * using __mmplayer_handle_streaming_error.
1480 __mmplayer_handle_streaming_error(player, msg);
1482 /* dump state of all element */
1483 _mmplayer_dump_pipeline_state(player);
1485 /* traslate gst error code to msl error code. then post it
1486 * to application if needed
1488 __mmplayer_handle_gst_error(player, msg, error);
1491 LOGE("error debug : %s", debug);
1494 MMPLAYER_FREEIF(debug);
1495 g_error_free(error);
1502 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1504 MMMessageParamType msg_param = {0, };
1505 int bRet = MM_ERROR_NONE;
1508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1510 if (!MMPLAYER_IS_STREAMING(player)) {
1511 LOGW("this is not streaming playback.");
1515 MMPLAYER_CMD_LOCK(player);
1517 if (!player->streamer) {
1518 LOGW("Pipeline is shutting down");
1519 MMPLAYER_CMD_UNLOCK(player);
1523 /* ignore the remained buffering message till getting 100% msg */
1524 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1525 gint buffer_percent = 0;
1527 gst_message_parse_buffering(msg, &buffer_percent);
1529 if (buffer_percent == MAX_BUFFER_PERCENT) {
1530 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1531 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1532 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1534 MMPLAYER_CMD_UNLOCK(player);
1538 /* ignore the remained buffering message */
1539 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1540 gint buffer_percent = 0;
1542 gst_message_parse_buffering(msg, &buffer_percent);
1544 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1545 player->streamer->buffering_percent, buffer_percent);
1547 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1548 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1549 player->streamer->buffering_req.is_pre_buffering = FALSE;
1551 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1553 LOGD("interrupted buffering - ignored the remained buffering msg!");
1554 MMPLAYER_CMD_UNLOCK(player);
1559 __mmplayer_update_buffer_setting(player, msg);
1561 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1563 if (bRet == MM_ERROR_NONE) {
1564 msg_param.connection.buffering = player->streamer->buffering_percent;
1565 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1567 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1568 player->pending_resume &&
1569 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1571 player->is_external_subtitle_added_now = FALSE;
1572 player->pending_resume = FALSE;
1573 _mmplayer_resume((MMHandleType)player);
1576 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1577 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1579 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1580 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1581 player->seek_state = MMPLAYER_SEEK_NONE;
1582 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1583 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1584 /* Considering the async state trasition in case of RTSP.
1585 After getting state change gst msg, seek cmpleted msg will be posted. */
1586 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1590 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1591 if (!player->streamer) {
1592 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1593 MMPLAYER_CMD_UNLOCK(player);
1597 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1599 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1600 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1602 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1603 msg_param.connection.buffering = player->streamer->buffering_percent;
1604 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1606 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1609 msg_param.connection.buffering = player->streamer->buffering_percent;
1610 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1613 MMPLAYER_CMD_UNLOCK(player);
1621 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1623 mmplayer_gst_element_t *mainbin;
1624 const GValue *voldstate, *vnewstate, *vpending;
1625 GstState oldstate = GST_STATE_NULL;
1626 GstState newstate = GST_STATE_NULL;
1627 GstState pending = GST_STATE_NULL;
1630 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1632 mainbin = player->pipeline->mainbin;
1634 /* we only handle messages from pipeline */
1635 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1638 /* get state info from msg */
1639 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1640 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1641 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1643 if (!voldstate || !vnewstate) {
1644 LOGE("received msg has wrong format.");
1648 oldstate = (GstState)voldstate->data[0].v_int;
1649 newstate = (GstState)vnewstate->data[0].v_int;
1651 pending = (GstState)vpending->data[0].v_int;
1653 LOGD("state changed [%s] : %s ---> %s final : %s",
1654 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1655 gst_element_state_get_name((GstState)oldstate),
1656 gst_element_state_get_name((GstState)newstate),
1657 gst_element_state_get_name((GstState)pending));
1659 if (newstate == GST_STATE_PLAYING) {
1660 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1662 int retVal = MM_ERROR_NONE;
1663 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1665 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1667 if (MM_ERROR_NONE != retVal)
1668 LOGE("failed to seek pending postion. just keep staying current position.");
1670 player->pending_seek.is_pending = false;
1674 if (oldstate == newstate) {
1675 LOGD("pipeline reports state transition to old state");
1680 case GST_STATE_PAUSED:
1682 gboolean prepare_async = FALSE;
1684 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1685 // managed prepare async case
1686 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1687 LOGD("checking prepare mode for async transition - %d", prepare_async);
1690 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1691 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1693 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1694 _mm_player_streaming_set_content_bitrate(player->streamer,
1695 player->total_maximum_bitrate, player->total_bitrate);
1697 if (player->pending_seek.is_pending) {
1698 LOGW("trying to do pending seek");
1699 MMPLAYER_CMD_LOCK(player);
1700 __mmplayer_gst_pending_seek(player);
1701 MMPLAYER_CMD_UNLOCK(player);
1707 case GST_STATE_PLAYING:
1709 if (MMPLAYER_IS_STREAMING(player)) {
1710 // managed prepare async case when buffering is completed
1711 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1712 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1713 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1714 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1716 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1718 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1719 if (player->streamer->buffering_percent < 100) {
1721 MMMessageParamType msg_param = {0, };
1722 LOGW("Posting Buffering Completed Message to Application !!!");
1724 msg_param.connection.buffering = 100;
1725 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1730 if (player->gapless.stream_changed) {
1731 _mmplayer_update_content_attrs(player, ATTR_ALL);
1732 player->gapless.stream_changed = FALSE;
1735 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1736 player->seek_state = MMPLAYER_SEEK_NONE;
1737 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1741 case GST_STATE_VOID_PENDING:
1742 case GST_STATE_NULL:
1743 case GST_STATE_READY:
1753 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1755 const gchar *structure_name;
1756 gint count = 0, idx = 0;
1757 MMHandleType attrs = 0;
1760 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1762 attrs = MMPLAYER_GET_ATTRS(player);
1764 LOGE("Failed to get content attribute");
1768 if (gst_message_get_structure(msg) == NULL)
1771 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1772 if (!structure_name)
1775 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1777 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1778 const GValue *var_info = NULL;
1780 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1781 if (var_info != NULL) {
1782 if (player->adaptive_info.var_list)
1783 g_list_free_full(player->adaptive_info.var_list, g_free);
1785 /* share addr or copy the list */
1786 player->adaptive_info.var_list =
1787 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1789 count = g_list_length(player->adaptive_info.var_list);
1791 stream_variant_t *temp = NULL;
1793 /* print out for debug */
1794 LOGD("num of variant_info %d", count);
1795 for (idx = 0; idx < count; idx++) {
1796 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1798 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1804 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1805 gint num_buffers = 0;
1806 gint extra_num_buffers = 0;
1808 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1809 LOGD("video_num_buffers : %d", num_buffers);
1810 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers);
1813 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1814 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1815 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers);
1820 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1821 _mmplayer_track_update_text_attr_info(player, msg);
1823 /* custom message */
1824 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1825 MMMessageParamType msg_param = {0,};
1826 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1827 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1830 /* custom message for RTSP attribute :
1831 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1832 sdp which has contents info is received when rtsp connection is opened.
1833 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1834 if (!strcmp(structure_name, "rtspsrc_properties")) {
1835 gchar *audio_codec = NULL;
1836 gchar *video_codec = NULL;
1837 gchar *video_frame_size = NULL;
1839 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1840 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1841 player->streaming_type = _mmplayer_get_stream_service_type(player);
1843 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1844 LOGD("rtsp_audio_codec : %s", audio_codec);
1846 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1848 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1849 LOGD("rtsp_video_codec : %s", video_codec);
1851 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1853 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1854 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1855 if (video_frame_size) {
1856 char *seperator = strchr(video_frame_size, '-');
1858 char video_width[10] = {0,};
1859 int frame_size_len = strlen(video_frame_size);
1860 int separtor_len = strlen(seperator);
1862 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1863 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, atoi(video_width));
1866 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, atoi(seperator));
1870 if (mm_attrs_commit_all(attrs))
1871 LOGE("failed to commit.");
1879 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1881 mmplayer_gst_element_t *mainbin;
1884 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1886 mainbin = player->pipeline->mainbin;
1888 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1890 /* we only handle messages from pipeline */
1891 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1894 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1895 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1896 player->seek_state = MMPLAYER_SEEK_NONE;
1897 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1898 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1899 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1900 LOGD("sync %s state(%s) with parent state(%s)",
1901 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1902 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1903 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1905 /* In case of streaming, pause is required before finishing seeking by buffering.
1906 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1907 Because the buffering state is controlled according to the state transition for force resume,
1908 the decodebin state should be paused as player state. */
1909 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1912 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1913 (player->streamer) &&
1914 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1915 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1916 GstQuery *query = NULL;
1917 gboolean busy = FALSE;
1920 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1921 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1922 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1923 gst_query_parse_buffering_percent(query, &busy, &percent);
1924 gst_query_unref(query);
1926 LOGD("buffered percent(%s): %d",
1927 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1931 __mmplayer_handle_buffering_playback(player);
1934 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1943 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1945 mmplayer_t *player = (mmplayer_t *)(data);
1947 MMPLAYER_RETURN_IF_FAIL(player);
1948 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1950 switch (GST_MESSAGE_TYPE(msg)) {
1951 case GST_MESSAGE_UNKNOWN:
1952 LOGD("unknown message received");
1955 case GST_MESSAGE_EOS:
1956 LOGD("GST_MESSAGE_EOS received");
1957 __mmplayer_gst_handle_eos_message(player, msg);
1960 case GST_MESSAGE_ERROR:
1961 __mmplayer_gst_handle_error_message(player, msg);
1964 case GST_MESSAGE_WARNING:
1967 GError *error = NULL;
1969 gst_message_parse_warning(msg, &error, &debug);
1971 LOGD("warning : %s", error->message);
1972 LOGD("debug : %s", debug);
1974 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1976 MMPLAYER_FREEIF(debug);
1977 g_error_free(error);
1981 case GST_MESSAGE_TAG:
1983 LOGD("GST_MESSAGE_TAG");
1984 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1985 LOGW("failed to extract tags from gstmessage");
1989 case GST_MESSAGE_BUFFERING:
1990 __mmplayer_gst_handle_buffering_message(player, msg);
1993 case GST_MESSAGE_STATE_CHANGED:
1994 __mmplayer_gst_handle_state_message(player, msg);
1997 case GST_MESSAGE_CLOCK_LOST:
1999 GstClock *clock = NULL;
2000 gboolean need_new_clock = FALSE;
2002 gst_message_parse_clock_lost(msg, &clock);
2003 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2005 if (!player->videodec_linked)
2006 need_new_clock = TRUE;
2007 else if (!player->ini.use_system_clock)
2008 need_new_clock = TRUE;
2010 if (need_new_clock) {
2011 LOGD("Provide clock is TRUE, do pause->resume");
2012 _mmplayer_gst_pause(player, FALSE);
2013 _mmplayer_gst_resume(player, FALSE);
2018 case GST_MESSAGE_NEW_CLOCK:
2020 GstClock *clock = NULL;
2021 gst_message_parse_new_clock(msg, &clock);
2022 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2026 case GST_MESSAGE_ELEMENT:
2027 __mmplayer_gst_handle_element_message(player, msg);
2030 case GST_MESSAGE_DURATION_CHANGED:
2032 LOGD("GST_MESSAGE_DURATION_CHANGED");
2033 if (!__mmplayer_gst_handle_duration(player, msg))
2034 LOGW("failed to update duration");
2038 case GST_MESSAGE_ASYNC_START:
2039 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2042 case GST_MESSAGE_ASYNC_DONE:
2043 __mmplayer_gst_handle_async_done_message(player, msg);
2045 case GST_MESSAGE_STREAM_COLLECTION:
2046 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2048 case GST_MESSAGE_STREAMS_SELECTED:
2049 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2052 #if 0 /* delete unnecessary logs */
2053 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2054 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2055 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2056 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2057 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2058 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2059 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2060 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2061 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2062 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2063 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2064 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2065 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2066 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2067 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2074 /* should not call 'gst_message_unref(msg)' */
2078 static GstBusSyncReply
2079 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2081 mmplayer_t *player = (mmplayer_t *)data;
2082 GstBusSyncReply reply = GST_BUS_DROP;
2084 if (!(player->pipeline && player->pipeline->mainbin)) {
2085 LOGE("player pipeline handle is null");
2086 return GST_BUS_PASS;
2089 if (!__mmplayer_gst_check_useful_message(player, message)) {
2090 gst_message_unref(message);
2091 return GST_BUS_DROP;
2094 switch (GST_MESSAGE_TYPE(message)) {
2095 case GST_MESSAGE_TAG:
2096 __mmplayer_gst_extract_tag_from_msg(player, message);
2100 GstTagList *tags = NULL;
2102 gst_message_parse_tag(message, &tags);
2104 LOGE("TAGS received from element \"%s\".",
2105 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2107 gst_tag_list_foreach(tags, print_tag, NULL);
2108 gst_tag_list_unref(tags);
2116 case GST_MESSAGE_DURATION_CHANGED:
2117 __mmplayer_gst_handle_duration(player, message);
2119 case GST_MESSAGE_ASYNC_DONE:
2120 /* NOTE:Don't call gst_callback directly
2121 * because previous frame can be showed even though this message is received for seek.
2124 reply = GST_BUS_PASS;
2128 if (reply == GST_BUS_DROP)
2129 gst_message_unref(message);
2135 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2137 GstElement *appsrc = element;
2138 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2139 GstBuffer *buffer = NULL;
2140 GstFlowReturn ret = GST_FLOW_OK;
2143 MMPLAYER_RETURN_IF_FAIL(element);
2144 MMPLAYER_RETURN_IF_FAIL(buf);
2146 buffer = gst_buffer_new();
2148 if (buf->offset < 0 || buf->len < 0) {
2149 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2153 if (buf->offset >= buf->len) {
2154 LOGD("call eos appsrc");
2155 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2159 if (buf->len - buf->offset < size)
2160 len = buf->len - buf->offset;
2162 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2163 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2164 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2166 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2167 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2173 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2175 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2177 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2179 buf->offset = (int)size;
2185 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2187 mmplayer_t *player = (mmplayer_t *)user_data;
2188 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2189 MMMessageParamType msg_param = {0,};
2190 guint64 current_level_bytes = 0;
2192 MMPLAYER_RETURN_IF_FAIL(player);
2194 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2195 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2196 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2197 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2199 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2203 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2205 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2207 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2208 msg_param.buffer_status.stream_type = stream_type;
2209 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2210 msg_param.buffer_status.bytes = current_level_bytes;
2212 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2216 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2218 mmplayer_t *player = (mmplayer_t *)user_data;
2219 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2220 MMMessageParamType msg_param = {0,};
2221 guint64 current_level_bytes = 0;
2223 MMPLAYER_RETURN_IF_FAIL(player);
2225 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2226 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2227 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2228 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2230 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2234 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2236 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2238 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2239 msg_param.buffer_status.stream_type = stream_type;
2240 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2241 msg_param.buffer_status.bytes = current_level_bytes;
2243 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2247 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2249 mmplayer_t *player = (mmplayer_t *)user_data;
2250 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2251 MMMessageParamType msg_param = {0,};
2253 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2255 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2256 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2257 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2258 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2260 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2264 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2266 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2267 msg_param.seek_data.stream_type = stream_type;
2268 msg_param.seek_data.offset = position;
2270 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2276 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2278 #define MAX_LEN_NAME 20
2280 gboolean ret = FALSE;
2281 GstPad *sinkpad = NULL;
2282 gchar *prefix = NULL;
2283 gchar dec_name[MAX_LEN_NAME] = {0, };
2284 main_element_id_e elem_id = MMPLAYER_M_NUM;
2286 mmplayer_gst_element_t *mainbin = NULL;
2287 GstElement *decodebin = NULL;
2288 GstCaps *dec_caps = NULL;
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2294 player->pipeline->mainbin, FALSE);
2295 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2297 mainbin = player->pipeline->mainbin;
2299 case MM_PLAYER_STREAM_TYPE_AUDIO:
2301 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2303 case MM_PLAYER_STREAM_TYPE_VIDEO:
2305 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2308 LOGE("invalid type %d", type);
2312 if (mainbin[elem_id].gst) {
2313 LOGE("elem(%d) is already created", elem_id);
2317 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2319 /* create decodebin */
2320 decodebin = gst_element_factory_make("decodebin", dec_name);
2322 LOGE("failed to create %s", dec_name);
2326 mainbin[elem_id].id = elem_id;
2327 mainbin[elem_id].gst = decodebin;
2329 /* raw pad handling signal */
2330 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2331 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2333 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2334 before looking for any elements that can handle that stream.*/
2335 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2336 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2338 /* This signal is emitted when a element is added to the bin.*/
2339 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2340 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2342 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2343 LOGE("failed to add new decodebin");
2347 dec_caps = gst_pad_query_caps(srcpad, NULL);
2349 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2350 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2351 gst_caps_unref(dec_caps);
2354 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2356 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2357 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2360 gst_object_unref(GST_OBJECT(sinkpad));
2362 gst_element_sync_state_with_parent(decodebin);
2368 gst_object_unref(GST_OBJECT(sinkpad));
2370 if (mainbin[elem_id].gst) {
2371 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2372 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2373 gst_object_unref(mainbin[elem_id].gst);
2374 mainbin[elem_id].gst = NULL;
2382 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2384 #define MAX_LEN_NAME 20
2385 mmplayer_gst_element_t *mainbin = NULL;
2386 gchar *prefix = NULL;
2387 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2389 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2390 GstElement *src = NULL, *queue = NULL;
2391 GstPad *srcpad = NULL;
2394 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2395 player->pipeline->mainbin, FALSE);
2397 mainbin = player->pipeline->mainbin;
2399 LOGD("type(%d) path is creating", type);
2401 case MM_PLAYER_STREAM_TYPE_AUDIO:
2403 if (mainbin[MMPLAYER_M_SRC].gst)
2404 src_id = MMPLAYER_M_2ND_SRC;
2406 src_id = MMPLAYER_M_SRC;
2407 queue_id = MMPLAYER_M_A_BUFFER;
2409 case MM_PLAYER_STREAM_TYPE_VIDEO:
2411 src_id = MMPLAYER_M_SRC;
2412 queue_id = MMPLAYER_M_V_BUFFER;
2414 case MM_PLAYER_STREAM_TYPE_TEXT:
2415 prefix = "subtitle";
2416 src_id = MMPLAYER_M_SUBSRC;
2417 queue_id = MMPLAYER_M_S_BUFFER;
2420 LOGE("invalid type %d", type);
2424 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2425 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2428 src = gst_element_factory_make("appsrc", src_name);
2430 LOGF("failed to create %s", src_name);
2434 mainbin[src_id].id = src_id;
2435 mainbin[src_id].gst = src;
2437 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2438 "caps", caps, NULL);
2440 /* size of many video frames are larger than default blocksize as 4096 */
2441 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2442 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2444 if (player->media_stream_buffer_max_size[type] > 0)
2445 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2447 if (player->media_stream_buffer_min_percent[type] > 0)
2448 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2450 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2451 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2453 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2454 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2455 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2456 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2457 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2458 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2461 queue = gst_element_factory_make("queue2", queue_name);
2463 LOGE("failed to create %s", queue_name);
2466 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2468 mainbin[queue_id].id = queue_id;
2469 mainbin[queue_id].gst = queue;
2471 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2472 LOGE("failed to add src");
2476 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2477 LOGE("failed to add queue");
2481 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2482 LOGE("failed to link src and queue");
2486 /* create decoder */
2487 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2489 LOGE("failed to get srcpad of queue");
2493 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2494 _mmplayer_gst_create_decoder(player, srcpad, caps);
2496 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2497 LOGE("failed to create decoder");
2498 gst_object_unref(GST_OBJECT(srcpad));
2502 gst_object_unref(GST_OBJECT(srcpad));
2506 if (mainbin[src_id].gst) {
2507 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2508 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2509 gst_object_unref(mainbin[src_id].gst);
2510 mainbin[src_id].gst = NULL;
2513 if (mainbin[queue_id].gst) {
2514 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2515 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2516 gst_object_unref(mainbin[queue_id].gst);
2517 mainbin[queue_id].gst = NULL;
2524 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2526 GstPad *sinkpad = NULL;
2527 GstCaps *caps = NULL;
2528 GstElement *new_element = NULL;
2529 GstStructure *str = NULL;
2530 const gchar *name = NULL;
2532 mmplayer_t *player = (mmplayer_t *)data;
2536 MMPLAYER_RETURN_IF_FAIL(element && pad);
2537 MMPLAYER_RETURN_IF_FAIL(player &&
2539 player->pipeline->mainbin);
2541 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2542 * num_dynamic_pad will decreased after creating a sinkbin.
2544 player->num_dynamic_pad++;
2545 LOGD("stream count inc : %d", player->num_dynamic_pad);
2547 caps = gst_pad_query_caps(pad, NULL);
2548 MMPLAYER_CHECK_NULL(caps);
2550 str = gst_caps_get_structure(caps, 0);
2551 name = gst_structure_get_string(str, "media");
2553 LOGE("cannot get mimetype from structure.");
2557 if (strstr(name, "video")) {
2559 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2561 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2562 if (player->v_stream_caps) {
2563 gst_caps_unref(player->v_stream_caps);
2564 player->v_stream_caps = NULL;
2567 new_element = gst_element_factory_make("fakesink", NULL);
2568 player->num_dynamic_pad--;
2573 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2574 LOGE("failed to autoplug for caps");
2578 gst_caps_unref(caps);
2583 /* excute new_element if created*/
2585 LOGD("adding new element to pipeline");
2587 /* set state to READY before add to bin */
2588 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2590 /* add new element to the pipeline */
2591 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2592 LOGE("failed to add autoplug element to bin");
2596 /* get pad from element */
2597 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2599 LOGE("failed to get sinkpad from autoplug element");
2604 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2605 LOGE("failed to link autoplug element");
2609 gst_object_unref(sinkpad);
2612 /* run. setting PLAYING here since streamming source is live source */
2613 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2617 gst_caps_unref(caps);
2623 STATE_CHANGE_FAILED:
2625 /* FIXIT : take care if new_element has already added to pipeline */
2627 gst_object_unref(GST_OBJECT(new_element));
2630 gst_object_unref(GST_OBJECT(sinkpad));
2633 gst_caps_unref(caps);
2635 /* FIXIT : how to inform this error to MSL ????? */
2636 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2637 * then post an error to application
2642 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2644 mmplayer_t *player = (mmplayer_t *)data;
2648 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2649 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2650 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2651 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2653 * [1] audio and video will be dumped with filesink.
2654 * [2] autoplugging is done by just using pad caps.
2655 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2656 * and the video will be dumped via filesink.
2658 if (player->num_dynamic_pad == 0) {
2659 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2661 if (!_mmplayer_gst_remove_fakesink(player,
2662 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2663 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2664 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2665 * source element are not same. To overcome this situation, this function will called
2666 * several places and several times. Therefore, this is not an error case.
2671 /* create dot before error-return. for debugging */
2672 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2674 player->no_more_pad = TRUE;
2680 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2682 GstElement *element = NULL;
2683 gchar *user_agent = NULL;
2684 MMHandleType attrs = 0;
2687 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2689 /* get profile attribute */
2690 attrs = MMPLAYER_GET_ATTRS(player);
2692 LOGE("failed to get content attribute");
2696 element = gst_element_factory_make("rtspsrc", "rtsp source");
2698 LOGE("failed to create rtspsrc element");
2703 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2705 SECURE_LOGD("user_agent : %s", user_agent);
2707 /* setting property to streaming source */
2708 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2710 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2712 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2713 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2714 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2715 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2721 void __mmplayer_http_src_setup(GstElement *element, GstElement *source, gpointer data)
2723 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2725 mmplayer_t *player = (mmplayer_t *)data;
2726 MMHandleType attrs = 0;
2727 gchar *user_agent, *cookies, **cookie_list;
2728 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2729 user_agent = cookies = NULL;
2733 MMPLAYER_RETURN_IF_FAIL(player);
2735 LOGD("source element %s", GST_ELEMENT_NAME(source));
2737 /* get profile attribute */
2738 attrs = MMPLAYER_GET_ATTRS(player);
2740 LOGE("failed to get content attribute");
2744 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2745 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2748 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2749 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2751 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2752 http_timeout = player->ini.http_timeout;
2755 SECURE_LOGD("cookies : %s", cookies);
2756 SECURE_LOGD("user_agent : %s", user_agent);
2757 LOGD("timeout : %d", http_timeout);
2759 /* setting property to streaming source */
2760 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2762 /* parsing cookies */
2763 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2764 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2765 g_strfreev(cookie_list);
2769 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2775 gint __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2776 GstStream * stream, gpointer data)
2778 GstStreamType stype = gst_stream_get_stream_type (stream);
2780 if (stype & GST_STREAM_TYPE_AUDIO)
2781 LOGW("AUDIO type 0x%X", stype);
2782 else if (stype & GST_STREAM_TYPE_VIDEO)
2783 LOGW("VIDEO type 0x%X", stype);
2784 else if (stype & GST_STREAM_TYPE_TEXT)
2785 LOGW("TEXT type 0x%X", stype);
2791 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2793 gchar *factory_name = NULL;
2794 mmplayer_t *player = (mmplayer_t *)data;
2796 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
2798 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
2799 factory_name, GST_ELEMENT_NAME(element));
2801 /* keep the first typefind reference only */
2802 if (!player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {
2803 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
2804 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst = element;
2806 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2807 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
2808 } else if (g_strrstr(factory_name, "parsebin")) {
2809 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
2810 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
2811 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2812 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
2814 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2815 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
2817 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2818 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2820 _mmplayer_gst_element_added((GstElement *)child, element, data);
2827 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2829 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
2834 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
2836 GstElement *uridecodebin3 = NULL;
2837 GstElement *decodebin3 = NULL, *multiqueue = NULL;
2840 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2842 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
2843 if (!uridecodebin3) {
2844 LOGE("failed to create uridecodebin3");
2849 SECURE_LOGD("uri : %s", player->profile.uri);
2851 decodebin3 = gst_bin_get_by_name((GstBin *)uridecodebin3, "decodebin3-0");
2854 g_object_set(G_OBJECT(decodebin3), "message-forward", TRUE, NULL);
2855 multiqueue = gst_bin_get_by_name((GstBin *)decodebin3, "multiqueue0");
2859 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
2860 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = multiqueue;
2862 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
2863 _mm_player_streaming_set_multiqueue(player->streamer, multiqueue);
2866 /* setting property to streaming source */
2867 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri, "message-forward", TRUE, NULL);
2869 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2870 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "source-setup", G_CALLBACK(__mmplayer_http_src_setup), (gpointer)player);
2872 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2873 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2875 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2876 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
2878 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
2881 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2882 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
2884 /* FIXME: need to be added for gapless playback
2885 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2886 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
2889 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2890 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
2892 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2893 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
2895 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2896 LOGW("[DASH] this is still experimental feature");
2899 return uridecodebin3;
2903 __mmplayer_gst_make_http_src(mmplayer_t *player)
2905 GstElement *element = NULL;
2906 MMHandleType attrs = 0;
2907 gchar *user_agent, *cookies, **cookie_list;
2908 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2909 user_agent = cookies = NULL;
2913 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2915 /* get profile attribute */
2916 attrs = MMPLAYER_GET_ATTRS(player);
2918 LOGE("failed to get content attribute");
2922 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2924 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2926 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2931 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2932 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2934 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2935 http_timeout = player->ini.http_timeout;
2938 SECURE_LOGD("location : %s", player->profile.uri);
2939 SECURE_LOGD("cookies : %s", cookies);
2940 SECURE_LOGD("user_agent : %s", user_agent);
2941 LOGD("timeout : %d", http_timeout);
2943 /* setting property to streaming source */
2944 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2945 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), NULL);
2947 /* parsing cookies */
2948 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2949 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2950 g_strfreev(cookie_list);
2954 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2956 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2957 LOGW("[DASH] this is still experimental feature");
2964 __mmplayer_gst_make_file_src(mmplayer_t *player)
2966 GstElement *element = NULL;
2969 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2971 LOGD("using filesrc for 'file://' handler");
2972 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2973 LOGE("failed to get storage info");
2977 element = gst_element_factory_make("filesrc", "source");
2979 LOGE("failed to create filesrc");
2983 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2990 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2992 mmplayer_t *player = (mmplayer_t *)data;
2994 g_return_val_if_fail(player, FALSE);
2995 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2997 gst_message_ref(msg);
2999 g_mutex_lock(&player->bus_msg_q_lock);
3000 g_queue_push_tail(player->bus_msg_q, msg);
3001 g_mutex_unlock(&player->bus_msg_q_lock);
3003 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3004 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3005 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3009 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3011 mmplayer_t *player = (mmplayer_t *)(data);
3012 GstMessage *msg = NULL;
3016 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3018 player->pipeline->mainbin &&
3019 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3022 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3024 LOGE("cannot get BUS from the pipeline");
3028 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3030 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3031 while (!player->bus_msg_thread_exit) {
3032 g_mutex_lock(&player->bus_msg_q_lock);
3033 msg = g_queue_pop_head(player->bus_msg_q);
3034 g_mutex_unlock(&player->bus_msg_q_lock);
3036 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3039 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3040 /* handle the gst msg */
3041 __mmplayer_gst_bus_msg_callback(msg, player);
3042 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3043 gst_message_unref(msg);
3046 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3047 gst_object_unref(GST_OBJECT(bus));
3054 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3056 gint64 dur_nsec = 0;
3059 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3061 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3062 return MM_ERROR_NONE;
3064 /* NOTE : duration cannot be zero except live streaming.
3065 * Since some element could have some timing problemn with quering duration, try again.
3067 if (player->duration == 0) {
3068 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3069 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3070 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3071 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3072 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3073 player->pending_seek.is_pending = true;
3074 player->pending_seek.pos = position;
3075 player->seek_state = MMPLAYER_SEEK_NONE;
3076 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3077 return MM_ERROR_PLAYER_NO_OP;
3079 player->seek_state = MMPLAYER_SEEK_NONE;
3080 return MM_ERROR_PLAYER_SEEK;
3083 player->duration = dur_nsec;
3086 if (player->duration > 0 && player->duration < position) {
3087 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3088 return MM_ERROR_INVALID_ARGUMENT;
3092 return MM_ERROR_NONE;
3096 __mmplayer_gst_check_seekable(mmplayer_t *player)
3098 GstQuery *query = NULL;
3099 gboolean seekable = FALSE;
3101 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3105 query = gst_query_new_seeking(GST_FORMAT_TIME);
3106 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3107 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3108 gst_query_unref(query);
3111 LOGW("non-seekable content");
3112 player->seek_state = MMPLAYER_SEEK_NONE;
3116 LOGW("failed to get seeking query");
3117 gst_query_unref(query); /* keep seeking operation */
3124 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3126 GstState element_state = GST_STATE_VOID_PENDING;
3127 GstState element_pending_state = GST_STATE_VOID_PENDING;
3128 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3132 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3133 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3135 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3138 ret = gst_element_set_state(element, state);
3139 if (ret == GST_STATE_CHANGE_FAILURE) {
3140 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3142 /* dump state of all element */
3143 _mmplayer_dump_pipeline_state(player);
3145 return MM_ERROR_PLAYER_INTERNAL;
3148 /* return here so state transition to be done in async mode */
3150 LOGD("async state transition. not waiting for state complete.");
3151 return MM_ERROR_NONE;
3154 /* wait for state transition */
3155 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3156 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3157 LOGE("failed to change [%s] element state to [%s] within %d sec",
3158 GST_ELEMENT_NAME(element),
3159 gst_element_state_get_name(state), timeout);
3161 LOGE(" [%s] state : %s pending : %s",
3162 GST_ELEMENT_NAME(element),
3163 gst_element_state_get_name(element_state),
3164 gst_element_state_get_name(element_pending_state));
3166 /* dump state of all element */
3167 _mmplayer_dump_pipeline_state(player);
3169 return MM_ERROR_PLAYER_INTERNAL;
3172 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3176 return MM_ERROR_NONE;
3180 _mmplayer_gst_start(mmplayer_t *player)
3182 int ret = MM_ERROR_NONE;
3183 gboolean async = FALSE;
3187 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3189 /* NOTE : if SetPosition was called before Start. do it now
3190 * streaming doesn't support it. so it should be always sync
3191 * !!create one more api to check if there is pending seek rather than checking variables
3193 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3194 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3195 ret = _mmplayer_gst_pause(player, FALSE);
3196 if (ret != MM_ERROR_NONE) {
3197 LOGE("failed to set state to PAUSED for pending seek");
3201 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3202 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3203 LOGW("failed to seek pending postion. starting from the begin of content");
3206 LOGD("current state before doing transition");
3207 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3208 MMPLAYER_PRINT_STATE(player);
3210 /* set pipeline state to PLAYING */
3211 ret = _mmplayer_gst_set_state(player,
3212 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3213 if (ret != MM_ERROR_NONE) {
3214 LOGE("failed to set state to PLAYING");
3218 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3220 /* generating debug info before returning error */
3221 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3229 _mmplayer_gst_stop(mmplayer_t *player)
3231 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3232 MMHandleType attrs = 0;
3233 gboolean rewind = FALSE;
3235 int ret = MM_ERROR_NONE;
3239 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3240 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3242 LOGD("current state before doing transition");
3243 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3244 MMPLAYER_PRINT_STATE(player);
3246 attrs = MMPLAYER_GET_ATTRS(player);
3248 LOGE("cannot get content attribute");
3249 return MM_ERROR_PLAYER_INTERNAL;
3252 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3253 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3255 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3256 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3259 if (player->es_player_push_mode)
3260 /* disable the async state transition because there could be no data in the pipeline */
3261 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3264 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3266 if (player->es_player_push_mode) {
3267 /* enable the async state transition as default operation */
3268 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3271 /* return if set_state has failed */
3272 if (ret != MM_ERROR_NONE) {
3273 LOGE("failed to set state.");
3279 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3280 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3281 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3282 LOGW("failed to rewind");
3283 ret = MM_ERROR_PLAYER_SEEK;
3288 player->sent_bos = FALSE;
3290 if (player->es_player_push_mode) //for cloudgame
3293 /* wait for seek to complete */
3294 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3295 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3296 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3298 LOGE("fail to stop player.");
3299 ret = MM_ERROR_PLAYER_INTERNAL;
3300 _mmplayer_dump_pipeline_state(player);
3303 /* generate dot file if enabled */
3304 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3312 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3314 int ret = MM_ERROR_NONE;
3318 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3319 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3321 LOGD("current state before doing transition");
3322 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3323 MMPLAYER_PRINT_STATE(player);
3325 /* set pipeline status to PAUSED */
3326 ret = _mmplayer_gst_set_state(player,
3327 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3332 if (ret != MM_ERROR_NONE) {
3333 GstMessage *msg = NULL;
3334 GTimer *timer = NULL;
3335 gdouble MAX_TIMEOUT_SEC = 3;
3337 LOGE("failed to set state to PAUSED");
3339 if (!player->bus_watcher) {
3340 LOGE("there is no bus msg thread. pipeline is shutting down.");
3344 if (player->msg_posted) {
3345 LOGE("error msg is already posted.");
3349 timer = g_timer_new();
3350 g_timer_start(timer);
3352 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3355 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3357 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3358 GError *error = NULL;
3360 /* parse error code */
3361 gst_message_parse_error(msg, &error, NULL);
3363 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3364 /* Note : the streaming error from the streaming source is handled
3365 * using __mmplayer_handle_streaming_error.
3367 __mmplayer_handle_streaming_error(player, msg);
3370 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3372 if (error->domain == GST_STREAM_ERROR)
3373 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3374 else if (error->domain == GST_RESOURCE_ERROR)
3375 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3376 else if (error->domain == GST_LIBRARY_ERROR)
3377 ret = __mmplayer_gst_handle_library_error(player, error->code);
3378 else if (error->domain == GST_CORE_ERROR)
3379 ret = __mmplayer_gst_handle_core_error(player, error->code);
3381 g_error_free(error);
3383 player->msg_posted = TRUE;
3385 gst_message_unref(msg);
3387 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3389 gst_object_unref(bus);
3390 g_timer_stop(timer);
3391 g_timer_destroy(timer);
3396 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3397 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3398 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3399 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3402 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3405 /* generate dot file before returning error */
3406 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3414 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3416 int ret = MM_ERROR_NONE;
3421 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3422 MM_ERROR_PLAYER_NOT_INITIALIZED);
3424 LOGD("current state before doing transition");
3425 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3426 MMPLAYER_PRINT_STATE(player);
3429 LOGD("do async state transition to PLAYING");
3431 /* set pipeline state to PLAYING */
3432 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3434 ret = _mmplayer_gst_set_state(player,
3435 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3436 if (ret != MM_ERROR_NONE) {
3437 LOGE("failed to set state to PLAYING");
3442 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3445 /* generate dot file */
3446 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3453 /* sending event to one of sinkelements */
3455 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3457 GstEvent *event2 = NULL;
3458 GList *sinks = NULL;
3459 gboolean res = FALSE;
3462 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3463 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3465 /* While adding subtitles in live feeds seek is getting called.
3466 Adding defensive check in framework layer.*/
3467 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3468 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3469 LOGE("Should not send seek event during live playback");
3474 if (player->play_subtitle)
3475 event2 = gst_event_copy((const GstEvent *)event);
3477 sinks = player->sink_elements;
3479 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3481 if (GST_IS_ELEMENT(sink)) {
3482 /* keep ref to the event */
3483 gst_event_ref(event);
3485 if ((res = gst_element_send_event(sink, event))) {
3486 LOGD("sending event[%s] to sink element [%s] success!",
3487 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3489 /* rtsp case, asyn_done is not called after seek during pause state */
3490 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3491 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3492 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3493 LOGD("RTSP seek completed, after pause state..");
3494 player->seek_state = MMPLAYER_SEEK_NONE;
3495 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3501 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3502 sinks = g_list_next(sinks);
3509 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3510 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3513 sinks = g_list_next(sinks);
3516 /* Note : Textbin is not linked to the video or audio bin.
3517 * It needs to send the event to the text sink seperatelly.
3519 if (player->play_subtitle && player->pipeline) {
3520 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3522 if (GST_IS_ELEMENT(text_sink)) {
3523 /* keep ref to the event */
3524 gst_event_ref(event2);
3526 if ((res = gst_element_send_event(text_sink, event2)))
3527 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3528 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3530 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3531 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3533 gst_event_unref(event2);
3537 gst_event_unref(event);
3545 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3546 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3547 gint64 cur, GstSeekType stop_type, gint64 stop)
3549 GstEvent *event = NULL;
3550 gboolean result = FALSE;
3554 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3556 if (player->pipeline && player->pipeline->textbin)
3557 __mmplayer_drop_subtitle(player, FALSE);
3559 event = gst_event_new_seek(rate, format, flags, cur_type,
3560 cur, stop_type, stop);
3562 result = _mmplayer_gst_send_event_to_sink(player, event);
3570 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3572 int ret = MM_ERROR_NONE;
3573 gint64 pos_nsec = 0;
3574 gboolean accurated = FALSE;
3575 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3578 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3579 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3581 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3582 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3585 ret = __mmplayer_gst_check_duration(player, position);
3586 if (ret != MM_ERROR_NONE) {
3587 LOGE("failed to check duration 0x%X", ret);
3588 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3591 if (!__mmplayer_gst_check_seekable(player))
3592 return MM_ERROR_PLAYER_NO_OP;
3594 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3595 position, player->playback_rate, player->duration);
3597 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3598 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3599 This causes problem is position calculation during normal pause resume scenarios also.
3600 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3601 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3602 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3603 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3604 LOGW("getting current position failed in seek");
3606 player->last_position = pos_nsec;
3607 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3610 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3611 LOGD("not completed seek");
3612 return MM_ERROR_PLAYER_DOING_SEEK;
3615 if (!internal_called)
3616 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3618 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3619 that's why set position through property. */
3620 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3621 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3622 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3623 (!player->videodec_linked) && (!player->audiodec_linked)) {
3625 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3626 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3628 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3629 player->seek_state = MMPLAYER_SEEK_NONE;
3630 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3632 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3634 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3636 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3638 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3639 GST_FORMAT_TIME, seek_flags,
3640 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3641 LOGE("failed to set position");
3646 /* NOTE : store last seeking point to overcome some bad operation
3647 * (returning zero when getting current position) of some elements
3649 player->last_position = position;
3651 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3652 if (player->playback_rate > 1.0)
3653 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3655 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3656 LOGD("buffering should be reset after seeking");
3657 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3658 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3662 return MM_ERROR_NONE;
3665 player->pending_seek.is_pending = true;
3666 player->pending_seek.pos = position;
3668 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3669 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3670 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3671 player->pending_seek.pos);
3673 return MM_ERROR_NONE;
3676 player->seek_state = MMPLAYER_SEEK_NONE;
3677 return MM_ERROR_PLAYER_SEEK;
3681 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3683 #define TRICKPLAY_OFFSET GST_MSECOND
3685 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3686 gint64 pos_nsec = 0;
3687 gboolean ret = TRUE;
3689 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3690 MM_ERROR_PLAYER_NOT_INITIALIZED);
3692 current_state = MMPLAYER_CURRENT_STATE(player);
3694 /* NOTE : query position except paused state to overcome some bad operation
3695 * please refer to below comments in details
3697 if (current_state != MM_PLAYER_STATE_PAUSED)
3698 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3700 /* NOTE : get last point to overcome some bad operation of some elements
3701 *(returning zero when getting current position in paused state
3702 * and when failed to get postion during seeking
3704 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3705 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3707 if (player->playback_rate < 0.0)
3708 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3710 pos_nsec = player->last_position;
3713 pos_nsec = player->last_position;
3715 player->last_position = pos_nsec;
3717 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3720 if (player->duration > 0 && pos_nsec > player->duration)
3721 pos_nsec = player->duration;
3723 player->last_position = pos_nsec;
3726 *position = pos_nsec;
3728 return MM_ERROR_NONE;
3732 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3734 #define STREAMING_IS_FINISHED 0
3735 #define BUFFERING_MAX_PER 100
3736 #define DEFAULT_PER_VALUE -1
3737 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3739 mmplayer_gst_element_t *mainbin = NULL;
3740 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3741 gint64 buffered_total = 0;
3742 gint64 position = 0;
3743 gint buffered_sec = -1;
3744 GstBufferingMode mode = GST_BUFFERING_STREAM;
3745 gint64 content_size_time = player->duration;
3746 guint64 content_size_bytes = player->http_content_size;
3748 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3750 player->pipeline->mainbin,
3751 MM_ERROR_PLAYER_NOT_INITIALIZED);
3753 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3758 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3759 /* and rtsp is not ready yet. */
3760 LOGW("it's only used for http streaming case");
3761 return MM_ERROR_PLAYER_NO_OP;
3764 if (content_size_time <= 0 || content_size_bytes <= 0) {
3765 LOGW("there is no content size");
3766 return MM_ERROR_NONE;
3769 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3770 LOGW("fail to get current position");
3771 return MM_ERROR_NONE;
3774 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3775 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3777 mainbin = player->pipeline->mainbin;
3778 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3780 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3781 GstQuery *query = NULL;
3782 gint byte_in_rate = 0, byte_out_rate = 0;
3783 gint64 estimated_total = 0;
3785 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3786 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3787 LOGW("fail to get buffering query from queue2");
3789 gst_query_unref(query);
3790 return MM_ERROR_NONE;
3793 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3794 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3796 if (mode == GST_BUFFERING_STREAM) {
3797 /* using only queue in case of push mode(ts / mp3) */
3798 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3799 GST_FORMAT_BYTES, &buffered_total)) {
3800 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3801 end_per = 100 * buffered_total / content_size_bytes;
3804 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3806 guint num_of_ranges = 0;
3807 gint64 start_byte = 0, stop_byte = 0;
3809 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3810 if (estimated_total != STREAMING_IS_FINISHED) {
3811 /* buffered size info from queue2 */
3812 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3813 for (idx = 0; idx < num_of_ranges; idx++) {
3814 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3815 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3817 buffered_total += (stop_byte - start_byte);
3820 end_per = BUFFERING_MAX_PER;
3823 gst_query_unref(query);
3826 if (end_per == DEFAULT_PER_VALUE) {
3827 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3829 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3831 /* buffered size info from multiqueue */
3832 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3833 guint curr_size_bytes = 0;
3834 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3835 "curr-size-bytes", &curr_size_bytes, NULL);
3836 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3837 buffered_total += curr_size_bytes;
3840 if (avg_byterate > 0)
3841 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3842 else if (player->total_maximum_bitrate > 0)
3843 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3844 else if (player->total_bitrate > 0)
3845 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3847 if (buffered_sec >= 0)
3848 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3852 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3853 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3855 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3856 buffered_total, buffered_sec, *start_pos, *end_pos);
3858 return MM_ERROR_NONE;
3862 _mmplayer_gst_create_source(mmplayer_t *player)
3864 GstElement *element = NULL;
3867 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3868 player->pipeline->mainbin, NULL);
3870 /* setup source for gapless play */
3871 switch (player->profile.uri_type) {
3873 case MM_PLAYER_URI_TYPE_FILE:
3874 element = __mmplayer_gst_make_file_src(player);
3876 case MM_PLAYER_URI_TYPE_URL_HTTP:
3877 element = __mmplayer_gst_make_http_src(player);
3880 LOGE("not support uri type %d", player->profile.uri_type);
3885 LOGE("failed to create source element");
3894 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3896 MMHandleType attrs = 0;
3899 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3900 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3902 /* get profile attribute */
3903 attrs = MMPLAYER_GET_ATTRS(player);
3905 LOGE("failed to get content attribute");
3906 return MM_ERROR_PLAYER_INTERNAL;
3909 SECURE_LOGD("uri : %s", player->profile.uri);
3911 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3912 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3913 LOGE("failed to commit");
3915 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3916 return MM_ERROR_PLAYER_INTERNAL;
3918 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3919 return MM_ERROR_PLAYER_INTERNAL;
3921 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3922 return MM_ERROR_PLAYER_INTERNAL;
3925 return MM_ERROR_NONE;
3929 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3931 mmplayer_gst_element_t *mainbin = NULL;
3932 GstElement *src_elem = NULL;
3933 GstElement *autoplug_elem = NULL;
3934 GList *element_bucket = NULL;
3935 MMHandleType attrs = 0;
3936 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3939 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3940 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3942 mainbin = player->pipeline->mainbin;
3944 /* get profile attribute */
3945 attrs = MMPLAYER_GET_ATTRS(player);
3947 LOGE("failed to get content attribute");
3948 return MM_ERROR_PLAYER_INTERNAL;
3951 LOGD("uri type %d", player->profile.uri_type);
3953 /* create source element */
3954 switch (player->profile.uri_type) {
3955 case MM_PLAYER_URI_TYPE_URL_RTSP:
3956 src_elem = __mmplayer_gst_make_rtsp_src(player);
3958 case MM_PLAYER_URI_TYPE_URL_HTTP:
3959 if (player->ini.use_uridecodebin3) { /* or MMPLAYER_USE_URIDECODEBIN3(player) */
3960 LOGD("uridecodebin include src element.");
3963 src_elem = __mmplayer_gst_make_http_src(player);
3965 case MM_PLAYER_URI_TYPE_FILE:
3966 src_elem = __mmplayer_gst_make_file_src(player);
3968 case MM_PLAYER_URI_TYPE_SS:
3970 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3971 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3973 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3977 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3978 LOGD("get timeout from ini");
3979 http_timeout = player->ini.http_timeout;
3982 /* setting property to streaming source */
3983 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3986 case MM_PLAYER_URI_TYPE_MEM:
3988 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3990 src_elem = gst_element_factory_make("appsrc", "mem-source");
3992 LOGE("failed to create appsrc element");
3996 g_object_set(src_elem, "stream-type", stream_type,
3997 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3999 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4000 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4001 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4002 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4006 LOGE("not support uri type");
4011 LOGE("failed to create source element");
4012 return MM_ERROR_PLAYER_INTERNAL;
4015 /* take source element */
4016 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4018 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4019 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4020 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4022 ADD_DECODEBIN: /* create next element for auto-plugging */
4023 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4024 if (!src_elem) { /* make uridecodebin3 which include src element */
4025 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4026 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4027 if (!autoplug_elem) {
4028 LOGE("failed to create uridecodebin3 element");
4032 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4033 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4034 if (!autoplug_elem) {
4035 LOGE("failed to create typefind element");
4038 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4039 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4041 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4042 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4043 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4044 if (!autoplug_elem) {
4045 LOGE("failed to create decodebin");
4049 /* default size of mq in decodebin is 2M
4050 * but it can cause blocking issue during seeking depends on content. */
4051 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4054 if (autoplug_elem) {
4055 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4056 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4057 mainbin[autoplug_elem_id].gst = autoplug_elem;
4059 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4062 /* add elements to pipeline */
4063 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4064 LOGE("failed to add elements to pipeline");
4068 /* linking elements in the bucket by added order. */
4069 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4070 LOGE("failed to link some elements");
4074 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4075 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4076 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4077 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4079 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4080 LOGE("failed to create fakesink");
4083 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4085 /* take ownership of fakesink. we are reusing it */
4086 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4088 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4089 LOGE("failed to add fakesink to bin");
4090 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4095 g_list_free(element_bucket);
4098 return MM_ERROR_NONE;
4101 g_list_free(element_bucket);
4103 if (mainbin[MMPLAYER_M_SRC].gst)
4104 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4106 if (mainbin[autoplug_elem_id].gst)
4107 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4109 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4110 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4112 mainbin[MMPLAYER_M_SRC].gst = NULL;
4113 mainbin[autoplug_elem_id].gst = NULL;
4114 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4116 return MM_ERROR_PLAYER_INTERNAL;
4120 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4123 mmplayer_gst_element_t *mainbin = NULL;
4126 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4127 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4129 mainbin = player->pipeline->mainbin;
4131 /* connect bus callback */
4132 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4134 LOGE("cannot get bus from pipeline");
4135 return MM_ERROR_PLAYER_INTERNAL;
4138 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4139 player->context.thread_default = g_main_context_get_thread_default();
4140 if (player->context.thread_default == NULL) {
4141 player->context.thread_default = g_main_context_default();
4142 LOGD("thread-default context is the global default context");
4144 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4146 /* set sync handler to get tag synchronously */
4147 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4148 gst_object_unref(GST_OBJECT(bus));
4150 /* create gst bus_msb_cb thread */
4151 g_mutex_init(&player->bus_msg_thread_mutex);
4152 g_cond_init(&player->bus_msg_thread_cond);
4153 player->bus_msg_thread_exit = FALSE;
4154 player->bus_msg_thread =
4155 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4156 if (!player->bus_msg_thread) {
4157 LOGE("failed to create gst BUS msg thread");
4158 g_mutex_clear(&player->bus_msg_thread_mutex);
4159 g_cond_clear(&player->bus_msg_thread_cond);
4160 return MM_ERROR_PLAYER_INTERNAL;
4164 return MM_ERROR_NONE;
4168 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4170 mmplayer_gst_element_t *mainbin = NULL;
4171 MMMessageParamType msg_param = {0,};
4172 GstElement *element = NULL;
4173 MMHandleType attrs = 0;
4175 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4179 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4180 LOGE("player is not initialized");
4184 mainbin = player->pipeline->mainbin;
4185 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4187 attrs = MMPLAYER_GET_ATTRS(player);
4189 LOGE("fail to get attributes");
4193 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4195 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4196 LOGE("failed to parse profile");
4197 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4201 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4202 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4203 LOGE("dash or hls is not supportable");
4204 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4208 element = _mmplayer_gst_create_source(player);
4210 LOGE("no source element was created");
4214 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4215 LOGE("failed to add source element to pipeline");
4216 gst_object_unref(GST_OBJECT(element));
4221 /* take source element */
4222 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4223 mainbin[MMPLAYER_M_SRC].gst = element;
4227 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4228 if (player->streamer == NULL) {
4229 player->streamer = _mm_player_streaming_create();
4230 _mm_player_streaming_initialize(player->streamer, TRUE);
4233 elem_idx = MMPLAYER_M_TYPEFIND;
4234 element = gst_element_factory_make("typefind", "typefinder");
4235 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4236 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4238 elem_idx = MMPLAYER_M_AUTOPLUG;
4239 element = _mmplayer_gst_make_decodebin(player);
4242 /* check autoplug element is OK */
4244 LOGE("can not create element(%d)", elem_idx);
4248 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4249 LOGE("failed to add sinkbin to pipeline");
4250 gst_object_unref(GST_OBJECT(element));
4255 mainbin[elem_idx].id = elem_idx;
4256 mainbin[elem_idx].gst = element;
4258 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4259 LOGE("Failed to link src - autoplug(or typefind)");
4263 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4264 LOGE("Failed to change state of src element");
4268 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4269 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4270 LOGE("Failed to change state of decodebin");
4274 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4275 LOGE("Failed to change state of src element");
4280 player->gapless.stream_changed = TRUE;
4281 player->gapless.running = TRUE;
4287 MMPLAYER_PLAYBACK_UNLOCK(player);
4289 if (!player->msg_posted) {
4290 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4291 player->msg_posted = TRUE;