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"
37 /*===========================================================================================
39 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
41 ========================================================================================== */
43 /*---------------------------------------------------------------------------
44 | GLOBAL CONSTANT DEFINITIONS: |
45 ---------------------------------------------------------------------------*/
47 /*---------------------------------------------------------------------------
48 | IMPORTED VARIABLE DECLARATIONS: |
49 ---------------------------------------------------------------------------*/
51 /*---------------------------------------------------------------------------
52 | IMPORTED FUNCTION DECLARATIONS: |
53 ---------------------------------------------------------------------------*/
55 /*---------------------------------------------------------------------------
57 ---------------------------------------------------------------------------*/
59 /*---------------------------------------------------------------------------
60 | LOCAL CONSTANT DEFINITIONS: |
61 ---------------------------------------------------------------------------*/
63 /*---------------------------------------------------------------------------
64 | LOCAL DATA TYPE DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | GLOBAL VARIABLE DEFINITIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | LOCAL VARIABLE DEFINITIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
76 | LOCAL FUNCTION PROTOTYPES: |
77 ---------------------------------------------------------------------------*/
79 /*===========================================================================================
81 | FUNCTION DEFINITIONS |
83 ========================================================================================== */
86 __mmplayer_check_error_posted_from_activated_track(mm_player_t *player, gchar *src_element_name)
88 /* check whether the error is posted from not-activated track or not */
90 gint active_pad_index = 0;
92 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
94 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
95 LOGD("current active pad index -%d", active_pad_index);
97 if (src_element_name) {
100 if (player->audio_decoders) {
101 GList *adec = player->audio_decoders;
102 for (; adec ; adec = g_list_next(adec)) {
103 gchar *name = adec->data;
105 LOGD("found audio decoder name = %s", name);
106 if (g_strrstr(name, src_element_name)) {
113 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
116 if (active_pad_index != msg_src_pos) {
117 LOGD("skip error because error is posted from no activated track");
125 __mmplayer_gst_transform_error_decode(mm_player_t *player, const char *klass)
127 /* Demuxer can't parse one track because it's corrupted.
128 * So, the decoder for it is not linked.
129 * But, it has one playable track.
131 if (g_strrstr(klass, "Demux")) {
132 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
133 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
134 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
135 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
137 if (player->pipeline->audiobin) { // PCM
138 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
140 LOGD("not found any available codec. Player should be destroyed.\n");
141 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
146 return MM_ERROR_PLAYER_INVALID_STREAM;
150 __mmplayer_gst_transform_error_type(mm_player_t *player, GstElement *src_element)
152 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
153 LOGE("Not supported subtitle.");
154 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
156 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
160 __mmplayer_gst_transform_error_failed(mm_player_t *player, const char *klass, GError *error)
162 /* Decoder Custom Message */
163 if (!strstr(error->message, "ongoing"))
164 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
166 if (strncasecmp(klass, "audio", 5)) {
167 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
168 LOGD("Video can keep playing.\n");
169 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
171 } else if (strncasecmp(klass, "video", 5)) {
172 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
173 LOGD("Audio can keep playing.\n");
174 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
178 LOGD("not found any available codec. Player should be destroyed.\n");
179 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
183 __mmplayer_gst_transform_error_decrypt(mm_player_t *player, GError *error)
185 if (strstr(error->message, "rights expired"))
186 return MM_ERROR_PLAYER_DRM_EXPIRED;
187 else if (strstr(error->message, "no rights"))
188 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
189 else if (strstr(error->message, "has future rights"))
190 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
191 else if (strstr(error->message, "opl violation"))
192 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
194 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
196 /* NOTE : decide gstreamer state whether there is some playable track or not. */
198 __mmplayer_gst_transform_gsterror(mm_player_t *player, GstMessage *message, GError *error)
200 gchar *src_element_name = NULL;
201 GstElement *src_element = NULL;
202 GstElementFactory *factory = NULL;
203 const gchar *klass = NULL;
207 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
208 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
209 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
212 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
214 src_element = GST_ELEMENT_CAST(message->src);
216 return MM_ERROR_PLAYER_INTERNAL;
218 src_element_name = GST_ELEMENT_NAME(src_element);
219 if (!src_element_name)
220 return MM_ERROR_PLAYER_INTERNAL;
222 factory = gst_element_get_factory(src_element);
224 return MM_ERROR_PLAYER_INTERNAL;
226 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
228 return MM_ERROR_PLAYER_INTERNAL;
230 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
231 error->code, error->message, src_element_name, klass);
233 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
234 return MM_ERROR_NONE;
236 switch (error->code) {
237 case GST_STREAM_ERROR_DECODE:
238 return __mmplayer_gst_transform_error_decode(player, klass);
239 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
240 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
241 case GST_STREAM_ERROR_WRONG_TYPE:
242 return __mmplayer_gst_transform_error_type(player, src_element);
243 case GST_STREAM_ERROR_FAILED:
244 return __mmplayer_gst_transform_error_failed(player, klass, error);
245 case GST_STREAM_ERROR_DECRYPT:
246 case GST_STREAM_ERROR_DECRYPT_NOKEY:
247 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
248 return __mmplayer_gst_transform_error_decrypt(player, error);
255 return MM_ERROR_PLAYER_INVALID_STREAM;
259 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
261 gint trans_err = MM_ERROR_NONE;
265 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
268 case GST_CORE_ERROR_MISSING_PLUGIN:
269 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
270 case GST_CORE_ERROR_STATE_CHANGE:
271 case GST_CORE_ERROR_SEEK:
272 case GST_CORE_ERROR_NOT_IMPLEMENTED:
273 case GST_CORE_ERROR_FAILED:
274 case GST_CORE_ERROR_TOO_LAZY:
275 case GST_CORE_ERROR_PAD:
276 case GST_CORE_ERROR_THREAD:
277 case GST_CORE_ERROR_NEGOTIATION:
278 case GST_CORE_ERROR_EVENT:
279 case GST_CORE_ERROR_CAPS:
280 case GST_CORE_ERROR_TAG:
281 case GST_CORE_ERROR_CLOCK:
282 case GST_CORE_ERROR_DISABLED:
284 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
294 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
296 gint trans_err = MM_ERROR_NONE;
300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
303 case GST_LIBRARY_ERROR_FAILED:
304 case GST_LIBRARY_ERROR_TOO_LAZY:
305 case GST_LIBRARY_ERROR_INIT:
306 case GST_LIBRARY_ERROR_SHUTDOWN:
307 case GST_LIBRARY_ERROR_SETTINGS:
308 case GST_LIBRARY_ERROR_ENCODE:
310 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
320 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
322 gint trans_err = MM_ERROR_NONE;
326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
329 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
330 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
332 case GST_RESOURCE_ERROR_NOT_FOUND:
333 case GST_RESOURCE_ERROR_OPEN_READ:
334 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
335 || MMPLAYER_IS_RTSP_STREAMING(player)) {
336 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
339 case GST_RESOURCE_ERROR_READ:
340 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
341 || MMPLAYER_IS_RTSP_STREAMING(player)) {
342 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
344 } else if (message != NULL && message->src != NULL) {
345 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
346 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
348 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
349 path_type = MMPLAYER_PATH_VOD;
350 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
351 path_type = MMPLAYER_PATH_TEXT;
353 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
354 /* check storage state */
355 storage_get_state(player->storage_info[path_type].id, &storage_state);
356 player->storage_info[path_type].state = storage_state;
357 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
360 case GST_RESOURCE_ERROR_WRITE:
361 case GST_RESOURCE_ERROR_FAILED:
362 case GST_RESOURCE_ERROR_SEEK:
363 case GST_RESOURCE_ERROR_TOO_LAZY:
364 case GST_RESOURCE_ERROR_BUSY:
365 case GST_RESOURCE_ERROR_OPEN_WRITE:
366 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
367 case GST_RESOURCE_ERROR_CLOSE:
368 case GST_RESOURCE_ERROR_SYNC:
369 case GST_RESOURCE_ERROR_SETTINGS:
371 trans_err = MM_ERROR_PLAYER_INTERNAL;
381 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
383 gint trans_err = MM_ERROR_NONE;
387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
388 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
389 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
391 switch (error->code) {
392 case GST_STREAM_ERROR_FAILED:
393 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
394 case GST_STREAM_ERROR_DECODE:
395 case GST_STREAM_ERROR_WRONG_TYPE:
396 case GST_STREAM_ERROR_DECRYPT:
397 case GST_STREAM_ERROR_DECRYPT_NOKEY:
398 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
399 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
402 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
403 case GST_STREAM_ERROR_TOO_LAZY:
404 case GST_STREAM_ERROR_ENCODE:
405 case GST_STREAM_ERROR_DEMUX:
406 case GST_STREAM_ERROR_MUX:
407 case GST_STREAM_ERROR_FORMAT:
409 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
419 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
421 MMMessageParamType msg_param;
422 gchar *msg_src_element;
426 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
427 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
429 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
431 memset(&msg_param, 0, sizeof(MMMessageParamType));
433 if (error->domain == GST_CORE_ERROR) {
434 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
435 } else if (error->domain == GST_LIBRARY_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
437 } else if (error->domain == GST_RESOURCE_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
439 } else if (error->domain == GST_STREAM_ERROR) {
440 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
442 LOGW("This error domain is not defined.\n");
444 /* we treat system error as an internal error */
445 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
449 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
451 msg_param.data = (void *) error->message;
453 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
454 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
458 if (msg_param.code == MM_ERROR_NONE)
461 /* skip error to avoid duplicated posting */
462 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
463 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
464 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
465 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
467 /* The error will be handled by mused.
468 * @ref _mmplayer_manage_external_storage_state() */
470 LOGW("storage is removed, skip error post");
474 /* post error to application */
475 if (!player->msg_posted) {
476 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
477 /* don't post more if one was sent already */
478 player->msg_posted = TRUE;
480 LOGD("skip error post because it's sent already.\n");
488 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
491 MMMessageParamType msg_param;
492 gchar *msg_src_element = NULL;
493 GstStructure *s = NULL;
495 gchar *error_string = NULL;
499 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
500 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
502 s = gst_structure_copy(gst_message_get_structure(message));
505 if (!gst_structure_get_uint(s, "error_id", &error_id))
506 error_id = MMPLAYER_STREAMING_ERROR_NONE;
509 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
510 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
512 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
515 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
518 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
521 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
524 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
527 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
530 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
533 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
536 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
539 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
542 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
545 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
548 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
551 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
554 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
557 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
560 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
563 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
566 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
569 case MMPLAYER_STREAMING_ERROR_GONE:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
572 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
575 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
578 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
581 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
584 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
587 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
590 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
593 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
596 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
599 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
602 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
605 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
608 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
611 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
614 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
617 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
620 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
623 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
626 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
629 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
632 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
635 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
636 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
638 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
639 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
641 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
642 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
646 gst_structure_free(s);
647 return MM_ERROR_PLAYER_STREAMING_FAIL;
651 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
653 msg_param.data = (void *) error_string;
656 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
658 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
659 msg_src_element, msg_param.code, (char*)msg_param.data);
662 /* post error to application */
663 if (!player->msg_posted) {
664 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
666 /* don't post more if one was sent already */
667 player->msg_posted = TRUE;
669 LOGD("skip error post because it's sent already.\n");
671 gst_structure_free(s);
672 g_free(error_string);
680 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
682 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
683 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
684 gst_tag_list_get_string(tags, "stitching_software",
685 &metadata->stitching_software);
686 gst_tag_list_get_string(tags, "projection_type",
687 &metadata->projection_type_string);
688 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
689 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
690 gst_tag_list_get_int(tags, "init_view_heading",
691 &metadata->init_view_heading);
692 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
693 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
694 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
695 gst_tag_list_get_int(tags, "full_pano_width_pixels",
696 &metadata->full_pano_width_pixels);
697 gst_tag_list_get_int(tags, "full_pano_height_pixels",
698 &metadata->full_pano_height_pixels);
699 gst_tag_list_get_int(tags, "cropped_area_image_width",
700 &metadata->cropped_area_image_width);
701 gst_tag_list_get_int(tags, "cropped_area_image_height",
702 &metadata->cropped_area_image_height);
703 gst_tag_list_get_int(tags, "cropped_area_left",
704 &metadata->cropped_area_left);
705 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
706 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
707 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
708 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
712 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
715 /* macro for better code readability */
716 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
717 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
718 if (string != NULL) { \
719 SECURE_LOGD("update tag string : %s\n", string); \
720 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
721 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
722 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
723 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
724 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
725 g_free(new_string); \
728 mm_attrs_set_string_by_name(attribute, playertag, string); \
735 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
737 GstSample *sample = NULL;\
738 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
739 GstMapInfo info = GST_MAP_INFO_INIT;\
740 buffer = gst_sample_get_buffer(sample);\
741 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
742 LOGD("failed to get image data from tag");\
743 gst_sample_unref(sample);\
746 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
747 MMPLAYER_FREEIF(player->album_art);\
748 player->album_art = (gchar *)g_malloc(info.size);\
749 if (player->album_art) {\
750 memcpy(player->album_art, info.data, info.size);\
751 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
752 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
753 msg_param.data = (void *)player->album_art;\
754 msg_param.size = info.size;\
755 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
756 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
759 gst_buffer_unmap(buffer, &info);\
760 gst_sample_unref(sample);\
764 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
766 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
769 gchar *tag_list_str = NULL; \
770 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
771 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
772 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
773 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
774 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
776 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
777 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
778 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
779 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
780 player->bitrate[track_type] = v_uint; \
781 player->total_bitrate = 0; \
782 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
783 player->total_bitrate += player->bitrate[i]; \
784 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
785 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
786 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
787 player->maximum_bitrate[track_type] = v_uint; \
788 player->total_maximum_bitrate = 0; \
789 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
790 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
791 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
792 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
794 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
797 g_free(tag_list_str); \
802 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
803 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
805 string = g_strdup_printf("%d", g_date_get_year(date));\
806 mm_attrs_set_string_by_name(attribute, playertag, string);\
807 SECURE_LOGD("metainfo year : %s\n", string);\
808 MMPLAYER_FREEIF(string);\
813 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
814 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
815 if (datetime != NULL) {\
816 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
817 mm_attrs_set_string_by_name(attribute, playertag, string);\
818 SECURE_LOGD("metainfo year : %s\n", string);\
819 MMPLAYER_FREEIF(string);\
820 gst_date_time_unref(datetime);\
824 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
825 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
827 /* FIXIT : don't know how to store date */\
833 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
834 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
836 /* FIXIT : don't know how to store date */\
843 GstTagList* tag_list = NULL;
845 MMHandleType attrs = 0;
850 GstDateTime *datetime = NULL;
852 GstBuffer *buffer = NULL;
854 MMMessageParamType msg_param = {0, };
856 /* currently not used. but those are needed for above macro */
857 //guint64 v_uint64 = 0;
858 //gdouble v_double = 0;
860 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
862 attrs = MMPLAYER_GET_ATTRS(player);
864 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
866 /* get tag list from gst message */
867 gst_message_parse_tag(msg, &tag_list);
869 /* store tags to player attributes */
870 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
871 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
872 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
873 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
874 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
876 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
877 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
878 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
879 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
882 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
883 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
884 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
885 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
886 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
887 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
888 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
889 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
891 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
892 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
899 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
901 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
902 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
903 MMPLAYER_UPDATE_TAG_LOCK(player);
904 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
905 MMPLAYER_UPDATE_TAG_UNLOCK(player);
906 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
907 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
909 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
910 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
911 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
912 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
913 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
914 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
915 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
916 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
917 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
918 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
920 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
921 if (player->video360_metadata.is_spherical == -1) {
922 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
923 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
924 player->video360_metadata.is_spherical);
925 if (player->video360_metadata.is_spherical == 1) {
926 LOGD("This is spherical content for 360 playback.");
927 player->is_content_spherical = TRUE;
929 LOGD("This is not spherical content");
930 player->is_content_spherical = FALSE;
933 if (player->video360_metadata.projection_type_string) {
934 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
935 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
937 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
938 player->is_content_spherical = player->is_video360_enabled = FALSE;
942 if (player->video360_metadata.stereo_mode_string) {
943 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
944 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
945 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
946 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
947 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
948 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
950 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
951 player->is_content_spherical = player->is_video360_enabled = FALSE;
957 if (mm_attrs_commit_all(attrs))
958 LOGE("failed to commit.\n");
960 gst_tag_list_free(tag_list);
965 /* if retval is FALSE, it will be dropped for perfomance. */
967 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
969 gboolean retval = FALSE;
971 if (!(player->pipeline && player->pipeline->mainbin)) {
972 LOGE("player pipeline handle is null");
976 switch (GST_MESSAGE_TYPE(message)) {
977 case GST_MESSAGE_TAG:
978 case GST_MESSAGE_EOS:
979 case GST_MESSAGE_ERROR:
980 case GST_MESSAGE_WARNING:
981 case GST_MESSAGE_CLOCK_LOST:
982 case GST_MESSAGE_NEW_CLOCK:
983 case GST_MESSAGE_ELEMENT:
984 case GST_MESSAGE_DURATION_CHANGED:
985 case GST_MESSAGE_ASYNC_START:
988 case GST_MESSAGE_ASYNC_DONE:
989 case GST_MESSAGE_STATE_CHANGED:
990 /* we only handle messages from pipeline */
991 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
996 case GST_MESSAGE_BUFFERING:
998 gint buffer_percent = 0;
1001 gst_message_parse_buffering(message, &buffer_percent);
1002 if (buffer_percent != MAX_BUFFER_PERCENT) {
1003 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1007 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1008 LOGW("can't get cmd lock, send msg to bus");
1012 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1013 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1014 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1017 MMPLAYER_CMD_UNLOCK(player);
1030 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1032 MMHandleType attrs = 0;
1033 guint64 data_size = 0;
1035 gint64 pos_nsec = 0;
1038 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1040 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1042 attrs = MMPLAYER_GET_ATTRS(player);
1044 LOGE("fail to get attributes.\n");
1048 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1049 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1051 if (stat(path, &sb) == 0)
1052 data_size = (guint64)sb.st_size;
1053 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1054 data_size = player->http_content_size;
1057 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1058 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1064 __mmplayer_handle_buffering_playback(mm_player_t* player)
1066 int ret = MM_ERROR_NONE;
1067 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1068 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1069 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1070 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1072 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1073 LOGW("do nothing for buffering msg\n");
1074 ret = MM_ERROR_PLAYER_INVALID_STATE;
1078 prev_state = MMPLAYER_PREV_STATE(player);
1079 current_state = MMPLAYER_CURRENT_STATE(player);
1080 target_state = MMPLAYER_TARGET_STATE(player);
1081 pending_state = MMPLAYER_PENDING_STATE(player);
1083 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1084 MMPLAYER_STATE_GET_NAME(prev_state),
1085 MMPLAYER_STATE_GET_NAME(current_state),
1086 MMPLAYER_STATE_GET_NAME(pending_state),
1087 MMPLAYER_STATE_GET_NAME(target_state),
1088 player->streamer->buffering_state);
1090 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1091 /* NOTE : if buffering has done, player has to go to target state. */
1092 switch (target_state) {
1093 case MM_PLAYER_STATE_PAUSED:
1095 switch (pending_state) {
1096 case MM_PLAYER_STATE_PLAYING:
1097 __mmplayer_gst_pause(player, TRUE);
1100 case MM_PLAYER_STATE_PAUSED:
1101 LOGD("player is already going to paused state, there is nothing to do.\n");
1104 case MM_PLAYER_STATE_NONE:
1105 case MM_PLAYER_STATE_NULL:
1106 case MM_PLAYER_STATE_READY:
1108 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1114 case MM_PLAYER_STATE_PLAYING:
1116 switch (pending_state) {
1117 case MM_PLAYER_STATE_NONE:
1119 if (current_state != MM_PLAYER_STATE_PLAYING)
1120 __mmplayer_gst_resume(player, TRUE);
1124 case MM_PLAYER_STATE_PAUSED:
1125 /* NOTE: It should be worked as asynchronously.
1126 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1128 if (current_state == MM_PLAYER_STATE_PLAYING) {
1129 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1130 * The current state should be changed to paused purposely to prevent state conflict.
1132 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1134 __mmplayer_gst_resume(player, TRUE);
1137 case MM_PLAYER_STATE_PLAYING:
1138 LOGD("player is already going to playing state, there is nothing to do.\n");
1141 case MM_PLAYER_STATE_NULL:
1142 case MM_PLAYER_STATE_READY:
1144 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1150 case MM_PLAYER_STATE_NULL:
1151 case MM_PLAYER_STATE_READY:
1152 case MM_PLAYER_STATE_NONE:
1154 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1158 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1159 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1161 switch (pending_state) {
1162 case MM_PLAYER_STATE_NONE:
1164 if (current_state != MM_PLAYER_STATE_PAUSED) {
1165 /* rtsp streaming pause makes rtsp server stop sending data. */
1166 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1167 LOGD("set pause state during buffering\n");
1168 __mmplayer_gst_pause(player, TRUE);
1174 case MM_PLAYER_STATE_PLAYING:
1175 /* rtsp streaming pause makes rtsp server stop sending data. */
1176 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1177 __mmplayer_gst_pause(player, TRUE);
1180 case MM_PLAYER_STATE_PAUSED:
1183 case MM_PLAYER_STATE_NULL:
1184 case MM_PLAYER_STATE_READY:
1186 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1195 static VariantData *
1196 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1198 VariantData *var_info = NULL;
1199 g_return_val_if_fail(self != NULL, NULL);
1201 var_info = g_new0(VariantData, 1);
1202 if (!var_info) return NULL;
1203 var_info->bandwidth = self->bandwidth;
1204 var_info->width = self->width;
1205 var_info->height = self->height;
1210 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1216 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1217 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1219 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1220 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1221 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1223 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1224 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1225 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1228 /* handling audio clip which has vbr. means duration is keep changing */
1229 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1238 __mmplayer_eos_timer_cb(gpointer u_data)
1240 mm_player_t* player = NULL;
1241 MMHandleType attrs = 0;
1244 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1246 player = (mm_player_t*) u_data;
1247 attrs = MMPLAYER_GET_ATTRS(player);
1249 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1253 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1254 if (ret_value != MM_ERROR_NONE)
1255 LOGE("seeking to 0 failed in repeat play");
1258 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1261 /* we are returning FALSE as we need only one posting */
1266 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1268 MMPLAYER_RETURN_IF_FAIL(player);
1270 /* post now if delay is zero */
1271 if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1272 LOGD("eos delay is zero. posting EOS now\n");
1273 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1275 if (player->audio_stream_render_cb)
1276 __mmplayer_cancel_eos_timer(player);
1281 /* cancel if existing */
1282 __mmplayer_cancel_eos_timer(player);
1284 /* init new timeout */
1285 /* NOTE : consider give high priority to this timer */
1286 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1288 player->eos_timer = g_timeout_add(delay_in_ms,
1289 __mmplayer_eos_timer_cb, player);
1291 player->context.global_default = g_main_context_default();
1292 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1294 /* check timer is valid. if not, send EOS now */
1295 if (player->eos_timer == 0) {
1296 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1297 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1301 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1303 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1304 int ret = MM_ERROR_NONE;
1308 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1310 if (!player->pending_seek.is_pending) {
1311 LOGD("pending seek is not reserved. nothing to do.\n");
1315 /* check player state if player could pending seek or not. */
1316 current_state = MMPLAYER_CURRENT_STATE(player);
1318 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1319 LOGW("try to pending seek in %s state, try next time. \n",
1320 MMPLAYER_STATE_GET_NAME(current_state));
1324 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1326 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1328 if (MM_ERROR_NONE != ret)
1329 LOGE("failed to seek pending postion. just keep staying current position.\n");
1331 player->pending_seek.is_pending = FALSE;
1339 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1341 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1343 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1345 audiobin = player->pipeline->audiobin; /* can be null */
1346 videobin = player->pipeline->videobin; /* can be null */
1347 textbin = player->pipeline->textbin; /* can be null */
1349 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1351 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1352 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1354 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1355 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1357 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1358 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1364 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1366 MMPlayerGstElement *textbin;
1369 MMPLAYER_RETURN_IF_FAIL(player &&
1371 player->pipeline->textbin);
1373 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1375 textbin = player->pipeline->textbin;
1378 LOGD("Drop subtitle text after getting EOS\n");
1380 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1381 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1383 player->is_subtitle_force_drop = TRUE;
1385 if (player->is_subtitle_force_drop == TRUE) {
1386 LOGD("Enable subtitle data path without drop\n");
1388 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1389 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1391 LOGD("non-connected with external display");
1393 player->is_subtitle_force_drop = FALSE;
1399 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1401 MMHandleType attrs = 0;
1406 /* NOTE : EOS event is comming multiple time. watch out it */
1407 /* check state. we only process EOS when pipeline state goes to PLAYING */
1408 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1409 LOGD("EOS received on non-playing state. ignoring it");
1413 if (player->pipeline && player->pipeline->textbin)
1414 __mmplayer_drop_subtitle(player, TRUE);
1416 if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1417 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1419 /* rewind if repeat count is greater then zero */
1420 /* get play count */
1421 attrs = MMPLAYER_GET_ATTRS(player);
1424 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1426 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1428 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1429 if (player->playback_rate < 0.0) {
1430 player->resumed_by_rewind = TRUE;
1431 _mmplayer_set_mute((MMHandleType)player, 0);
1432 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1435 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1438 player->sent_bos = FALSE;
1440 LOGD("do not post eos msg for repeating");
1445 if (player->pipeline)
1446 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1448 /* post eos message to application */
1449 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1451 /* reset last position */
1452 player->last_position = 0;
1459 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1461 GError *error = NULL;
1462 gchar* debug = NULL;
1466 /* generating debug info before returning error */
1467 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1469 /* get error code */
1470 gst_message_parse_error(msg, &error, &debug);
1472 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1473 /* Note : the streaming error from the streaming source is handled
1474 * using __mmplayer_handle_streaming_error.
1476 __mmplayer_handle_streaming_error(player, msg);
1478 /* dump state of all element */
1479 __mmplayer_dump_pipeline_state(player);
1481 /* traslate gst error code to msl error code. then post it
1482 * to application if needed
1484 __mmplayer_handle_gst_error(player, msg, error);
1487 LOGE("error debug : %s", debug);
1490 if (MMPLAYER_IS_HTTP_PD(player))
1491 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1493 MMPLAYER_FREEIF(debug);
1494 g_error_free(error);
1501 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1503 MMMessageParamType msg_param = {0, };
1504 int bRet = MM_ERROR_NONE;
1507 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1509 if (!MMPLAYER_IS_STREAMING(player)) {
1510 LOGW("this is not streaming playback.");
1514 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1515 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1516 /* skip the playback control by buffering msg while user request is handled. */
1519 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1521 gst_message_parse_buffering(msg, &per);
1522 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1524 msg_param.connection.buffering = per;
1525 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1529 MMPLAYER_CMD_LOCK(player);
1532 if (!player->streamer) {
1533 LOGW("Pipeline is shutting down");
1534 MMPLAYER_CMD_UNLOCK(player);
1538 /* ignore the remained buffering message till getting 100% msg */
1539 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1540 gint buffer_percent = 0;
1542 gst_message_parse_buffering(msg, &buffer_percent);
1544 if (buffer_percent == MAX_BUFFER_PERCENT) {
1545 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1546 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1548 MMPLAYER_CMD_UNLOCK(player);
1552 /* ignore the remained buffering message */
1553 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1554 gint buffer_percent = 0;
1556 gst_message_parse_buffering(msg, &buffer_percent);
1558 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1559 player->streamer->buffering_percent, buffer_percent);
1561 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1562 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1563 player->streamer->buffering_req.is_pre_buffering = FALSE;
1565 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1567 LOGD("interrupted buffering - ignored the remained buffering msg!");
1568 MMPLAYER_CMD_UNLOCK(player);
1573 __mmplayer_update_buffer_setting(player, msg);
1575 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1577 if (bRet == MM_ERROR_NONE) {
1578 msg_param.connection.buffering = player->streamer->buffering_percent;
1579 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1581 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1582 player->pending_resume &&
1583 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1585 player->is_external_subtitle_added_now = FALSE;
1586 player->pending_resume = FALSE;
1587 _mmplayer_resume((MMHandleType)player);
1590 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1591 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1593 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1594 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1595 player->seek_state = MMPLAYER_SEEK_NONE;
1596 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1597 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1598 /* Considering the async state trasition in case of RTSP.
1599 After getting state change gst msg, seek cmpleted msg will be posted. */
1600 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1604 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1605 if (!player->streamer) {
1606 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1607 MMPLAYER_CMD_UNLOCK(player);
1611 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1613 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1614 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1616 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1617 msg_param.connection.buffering = player->streamer->buffering_percent;
1618 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1620 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1623 msg_param.connection.buffering = player->streamer->buffering_percent;
1624 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1627 MMPLAYER_CMD_UNLOCK(player);
1635 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1637 MMPlayerGstElement *mainbin;
1638 const GValue *voldstate, *vnewstate, *vpending;
1639 GstState oldstate = GST_STATE_NULL;
1640 GstState newstate = GST_STATE_NULL;
1641 GstState pending = GST_STATE_NULL;
1644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1646 mainbin = player->pipeline->mainbin;
1648 /* we only handle messages from pipeline */
1649 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1652 /* get state info from msg */
1653 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1654 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1655 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1657 if (!voldstate || !vnewstate) {
1658 LOGE("received msg has wrong format.");
1662 oldstate = (GstState)voldstate->data[0].v_int;
1663 newstate = (GstState)vnewstate->data[0].v_int;
1665 pending = (GstState)vpending->data[0].v_int;
1667 LOGD("state changed [%s] : %s ---> %s final : %s",
1668 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1669 gst_element_state_get_name((GstState)oldstate),
1670 gst_element_state_get_name((GstState)newstate),
1671 gst_element_state_get_name((GstState)pending));
1673 if (newstate == GST_STATE_PLAYING) {
1674 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1676 int retVal = MM_ERROR_NONE;
1677 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1679 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1681 if (MM_ERROR_NONE != retVal)
1682 LOGE("failed to seek pending postion. just keep staying current position.");
1684 player->pending_seek.is_pending = FALSE;
1688 if (oldstate == newstate) {
1689 LOGD("pipeline reports state transition to old state");
1694 case GST_STATE_PAUSED:
1696 gboolean prepare_async = FALSE;
1698 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1699 // managed prepare async case
1700 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1701 LOGD("checking prepare mode for async transition - %d", prepare_async);
1704 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1705 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1707 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1708 __mm_player_streaming_set_content_bitrate(player->streamer,
1709 player->total_maximum_bitrate, player->total_bitrate);
1711 if (player->pending_seek.is_pending) {
1712 LOGW("trying to do pending seek");
1713 MMPLAYER_CMD_LOCK(player);
1714 __mmplayer_gst_pending_seek(player);
1715 MMPLAYER_CMD_UNLOCK(player);
1721 case GST_STATE_PLAYING:
1723 if (MMPLAYER_IS_STREAMING(player)) {
1724 // managed prepare async case when buffering is completed
1725 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1726 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1727 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1728 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1730 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1732 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1733 if (player->streamer->buffering_percent < 100) {
1735 MMMessageParamType msg_param = {0, };
1736 LOGW("Posting Buffering Completed Message to Application !!!");
1738 msg_param.connection.buffering = 100;
1739 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1744 if (player->gapless.stream_changed) {
1745 __mmplayer_update_content_attrs(player, ATTR_ALL);
1746 player->gapless.stream_changed = FALSE;
1749 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1750 player->seek_state = MMPLAYER_SEEK_NONE;
1751 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1755 case GST_STATE_VOID_PENDING:
1756 case GST_STATE_NULL:
1757 case GST_STATE_READY:
1767 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1769 const gchar *structure_name;
1770 gint count = 0, idx = 0;
1771 MMHandleType attrs = 0;
1774 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1776 attrs = MMPLAYER_GET_ATTRS(player);
1778 LOGE("Failed to get content attribute");
1782 if (gst_message_get_structure(msg) == NULL)
1785 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1786 if (!structure_name)
1789 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1791 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1792 const GValue *var_info = NULL;
1794 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1795 if (var_info != NULL) {
1796 if (player->adaptive_info.var_list)
1797 g_list_free_full(player->adaptive_info.var_list, g_free);
1799 /* share addr or copy the list */
1800 player->adaptive_info.var_list =
1801 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1803 count = g_list_length(player->adaptive_info.var_list);
1805 VariantData *temp = NULL;
1807 /* print out for debug */
1808 LOGD("num of variant_info %d", count);
1809 for (idx = 0; idx < count; idx++) {
1810 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1812 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1818 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1819 gint num_buffers = 0;
1820 gint extra_num_buffers = 0;
1822 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1823 player->video_num_buffers = num_buffers;
1824 LOGD("video_num_buffers : %d", player->video_num_buffers);
1827 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1828 player->video_extra_num_buffers = extra_num_buffers;
1829 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1834 if (!strcmp(structure_name, "Language_list")) {
1835 const GValue *lang_list = NULL;
1836 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1837 if (lang_list != NULL) {
1838 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1840 LOGD("Total audio tracks(from parser) = %d \n", count);
1844 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1845 const GValue *lang_list = NULL;
1846 MMPlayerLangStruct *temp = NULL;
1848 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1849 if (lang_list != NULL) {
1850 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1852 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1853 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1854 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1855 if (mm_attrs_commit_all(attrs))
1856 LOGE("failed to commit");
1858 LOGD("the num of external subtitle track: %d", count);
1860 while (count) { /* track lang info */
1861 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1863 LOGD("value of lang_key is %s and lang_code is %s",
1864 temp->language_key, temp->language_code);
1867 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1868 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1873 /* custom message */
1874 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1875 MMMessageParamType msg_param = {0,};
1876 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1877 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1880 /* custom message for RTSP attribute :
1881 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1882 sdp which has contents info is received when rtsp connection is opened.
1883 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1884 if (!strcmp(structure_name, "rtspsrc_properties")) {
1886 gchar *audio_codec = NULL;
1887 gchar *video_codec = NULL;
1888 gchar *video_frame_size = NULL;
1890 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1891 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1892 player->streaming_type = __mmplayer_get_stream_service_type(player);
1894 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1895 LOGD("rtsp_audio_codec : %s", audio_codec);
1897 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1899 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1900 LOGD("rtsp_video_codec : %s", video_codec);
1902 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1904 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1905 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1906 if (video_frame_size) {
1908 char *seperator = strchr(video_frame_size, '-');
1911 char video_width[10] = {0,};
1912 int frame_size_len = strlen(video_frame_size);
1913 int separtor_len = strlen(seperator);
1915 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1916 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1919 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1923 if (mm_attrs_commit_all(attrs))
1924 LOGE("failed to commit.\n");
1932 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1934 MMPlayerGstElement *mainbin;
1937 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1939 mainbin = player->pipeline->mainbin;
1941 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1943 /* we only handle messages from pipeline */
1944 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1947 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1948 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1949 player->seek_state = MMPLAYER_SEEK_NONE;
1950 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1951 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1952 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1953 LOGD("sync %s state(%s) with parent state(%s)",
1954 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1955 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1956 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1958 /* In case of streaming, pause is required before finishing seeking by buffering.
1959 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1960 Because the buffering state is controlled according to the state transition for force resume,
1961 the decodebin state should be paused as player state. */
1962 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1965 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1966 (player->streamer) &&
1967 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1968 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1969 GstQuery *query = NULL;
1970 gboolean busy = FALSE;
1973 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1974 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1975 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1976 gst_query_parse_buffering_percent(query, &busy, &percent);
1977 gst_query_unref(query);
1979 LOGD("buffered percent(%s): %d\n",
1980 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1984 __mmplayer_handle_buffering_playback(player);
1987 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1996 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1998 mm_player_t* player = (mm_player_t*)(data);
2000 MMPLAYER_RETURN_IF_FAIL(player);
2001 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2003 switch (GST_MESSAGE_TYPE(msg)) {
2004 case GST_MESSAGE_UNKNOWN:
2005 LOGD("unknown message received\n");
2008 case GST_MESSAGE_EOS:
2009 LOGD("GST_MESSAGE_EOS received");
2010 __mmplayer_gst_handle_eos_message(player, msg);
2013 case GST_MESSAGE_ERROR:
2014 __mmplayer_gst_handle_error_message(player, msg);
2017 case GST_MESSAGE_WARNING:
2020 GError* error = NULL;
2022 gst_message_parse_warning(msg, &error, &debug);
2024 LOGD("warning : %s\n", error->message);
2025 LOGD("debug : %s\n", debug);
2027 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2029 MMPLAYER_FREEIF(debug);
2030 g_error_free(error);
2034 case GST_MESSAGE_TAG:
2036 LOGD("GST_MESSAGE_TAG\n");
2037 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2038 LOGW("failed to extract tags from gstmessage\n");
2042 case GST_MESSAGE_BUFFERING:
2043 __mmplayer_gst_handle_buffering_message(player, msg);
2046 case GST_MESSAGE_STATE_CHANGED:
2047 __mmplayer_gst_handle_state_message(player, msg);
2050 case GST_MESSAGE_CLOCK_LOST:
2052 GstClock *clock = NULL;
2053 gboolean need_new_clock = FALSE;
2055 gst_message_parse_clock_lost(msg, &clock);
2056 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2058 if (!player->videodec_linked)
2059 need_new_clock = TRUE;
2060 else if (!player->ini.use_system_clock)
2061 need_new_clock = TRUE;
2063 if (need_new_clock) {
2064 LOGD("Provide clock is TRUE, do pause->resume\n");
2065 __mmplayer_gst_pause(player, FALSE);
2066 __mmplayer_gst_resume(player, FALSE);
2071 case GST_MESSAGE_NEW_CLOCK:
2073 GstClock *clock = NULL;
2074 gst_message_parse_new_clock(msg, &clock);
2075 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2079 case GST_MESSAGE_ELEMENT:
2080 __mmplayer_gst_handle_element_message(player, msg);
2083 case GST_MESSAGE_DURATION_CHANGED:
2085 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2086 if (!__mmplayer_gst_handle_duration(player, msg))
2087 LOGW("failed to update duration");
2091 case GST_MESSAGE_ASYNC_START:
2092 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2095 case GST_MESSAGE_ASYNC_DONE:
2096 __mmplayer_gst_handle_async_done_message(player, msg);
2099 #if 0 /* delete unnecessary logs */
2100 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2101 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2102 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2103 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2104 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2105 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2106 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2107 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2108 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2109 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2110 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2111 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2112 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2113 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2114 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2121 /* should not call 'gst_message_unref(msg)' */
2125 static GstBusSyncReply
2126 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2128 mm_player_t *player = (mm_player_t *)data;
2129 GstBusSyncReply reply = GST_BUS_DROP;
2131 if (!(player->pipeline && player->pipeline->mainbin)) {
2132 LOGE("player pipeline handle is null");
2133 return GST_BUS_PASS;
2136 if (!__mmplayer_gst_check_useful_message(player, message)) {
2137 gst_message_unref(message);
2138 return GST_BUS_DROP;
2141 switch (GST_MESSAGE_TYPE(message)) {
2142 case GST_MESSAGE_TAG:
2143 __mmplayer_gst_extract_tag_from_msg(player, message);
2147 GstTagList *tags = NULL;
2149 gst_message_parse_tag(message, &tags);
2151 LOGE("TAGS received from element \"%s\".\n",
2152 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2154 gst_tag_list_foreach(tags, print_tag, NULL);
2155 gst_tag_list_free(tags);
2163 case GST_MESSAGE_DURATION_CHANGED:
2164 __mmplayer_gst_handle_duration(player, message);
2166 case GST_MESSAGE_ASYNC_DONE:
2167 /* NOTE:Don't call gst_callback directly
2168 * because previous frame can be showed even though this message is received for seek.
2171 reply = GST_BUS_PASS;
2175 if (reply == GST_BUS_DROP)
2176 gst_message_unref(message);
2182 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2184 GstElement *appsrc = element;
2185 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2186 GstBuffer *buffer = NULL;
2187 GstFlowReturn ret = GST_FLOW_OK;
2190 MMPLAYER_RETURN_IF_FAIL(element);
2191 MMPLAYER_RETURN_IF_FAIL(buf);
2193 buffer = gst_buffer_new();
2195 if (buf->offset < 0 || buf->len < 0) {
2196 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2200 if (buf->offset >= buf->len) {
2201 LOGD("call eos appsrc");
2202 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2206 if (buf->len - buf->offset < size)
2207 len = buf->len - buf->offset;
2209 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2210 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2211 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2213 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2214 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2220 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2222 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2224 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2226 buf->offset = (int)size;
2232 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2234 mm_player_t *player = (mm_player_t*)user_data;
2235 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2236 guint64 current_level_bytes = 0;
2238 MMPLAYER_RETURN_IF_FAIL(player);
2240 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2241 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2242 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2243 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2244 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2245 type = MM_PLAYER_STREAM_TYPE_TEXT;
2247 LOGE("can not enter here");
2251 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2253 LOGI("type: %d, level: %llu", type, current_level_bytes);
2255 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2256 if (player->media_stream_buffer_status_cb[type])
2257 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2258 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2262 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2264 mm_player_t *player = (mm_player_t*)user_data;
2265 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2266 guint64 current_level_bytes = 0;
2268 MMPLAYER_RETURN_IF_FAIL(player);
2270 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2271 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2272 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2273 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2274 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2275 type = MM_PLAYER_STREAM_TYPE_TEXT;
2277 LOGE("can not enter here");
2281 LOGI("type: %d, buffer is full", type);
2283 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2285 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2287 if (player->media_stream_buffer_status_cb[type])
2288 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2290 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2294 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2296 mm_player_t *player = (mm_player_t*)user_data;
2297 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2299 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2301 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2302 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2303 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2304 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2305 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2306 type = MM_PLAYER_STREAM_TYPE_TEXT;
2308 LOGE("can not enter here");
2312 LOGD("type: %d, pos: %llu", type, position);
2313 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2315 if (player->media_stream_seek_data_cb[type])
2316 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2317 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2323 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2325 #define MAX_LEN_NAME 20
2327 gboolean ret = FALSE;
2328 GstPad *sinkpad = NULL;
2329 gchar *prefix = NULL;
2330 gchar dec_name[MAX_LEN_NAME] = {0};
2331 enum MainElementID elem_id = MMPLAYER_M_NUM;
2333 MMPlayerGstElement *mainbin = NULL;
2334 GstElement *decodebin = NULL;
2335 GstCaps *dec_caps = NULL;
2339 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2341 player->pipeline->mainbin, FALSE);
2342 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2344 mainbin = player->pipeline->mainbin;
2346 case MM_PLAYER_STREAM_TYPE_AUDIO:
2348 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2350 case MM_PLAYER_STREAM_TYPE_VIDEO:
2352 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2355 LOGE("invalid type %d", type);
2359 if (mainbin[elem_id].gst) {
2360 LOGE("elem(%d) is already created", elem_id);
2364 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2366 /* create decodebin */
2367 decodebin = gst_element_factory_make("decodebin", dec_name);
2369 LOGE("failed to create %s", dec_name);
2373 mainbin[elem_id].id = elem_id;
2374 mainbin[elem_id].gst = decodebin;
2376 /* raw pad handling signal */
2377 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2378 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2380 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2381 before looking for any elements that can handle that stream.*/
2382 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2383 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2385 /* This signal is emitted when a element is added to the bin.*/
2386 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2387 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2389 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2390 LOGE("failed to add new decodebin");
2394 dec_caps = gst_pad_query_caps(srcpad, NULL);
2396 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2397 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2398 gst_caps_unref(dec_caps);
2401 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2403 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2404 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2407 gst_object_unref(GST_OBJECT(sinkpad));
2409 gst_element_sync_state_with_parent(decodebin);
2415 gst_object_unref(GST_OBJECT(sinkpad));
2417 if (mainbin[elem_id].gst) {
2418 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2419 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2420 gst_object_unref(mainbin[elem_id].gst);
2421 mainbin[elem_id].gst = NULL;
2429 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2431 #define MAX_LEN_NAME 20
2432 MMPlayerGstElement *mainbin = NULL;
2433 gchar *prefix = NULL;
2434 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2436 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2437 GstElement *src = NULL, *queue = NULL;
2438 GstPad *srcpad = NULL;
2441 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2442 player->pipeline->mainbin, FALSE);
2444 mainbin = player->pipeline->mainbin;
2446 LOGD("type(%d) path is creating", type);
2448 case MM_PLAYER_STREAM_TYPE_AUDIO:
2450 if (mainbin[MMPLAYER_M_SRC].gst)
2451 src_id = MMPLAYER_M_2ND_SRC;
2453 src_id = MMPLAYER_M_SRC;
2454 queue_id = MMPLAYER_M_A_BUFFER;
2456 case MM_PLAYER_STREAM_TYPE_VIDEO:
2458 src_id = MMPLAYER_M_SRC;
2459 queue_id = MMPLAYER_M_V_BUFFER;
2461 case MM_PLAYER_STREAM_TYPE_TEXT:
2462 prefix = "subtitle";
2463 src_id = MMPLAYER_M_SUBSRC;
2464 queue_id = MMPLAYER_M_S_BUFFER;
2467 LOGE("invalid type %d", type);
2471 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2472 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2475 src = gst_element_factory_make("appsrc", src_name);
2477 LOGF("failed to create %s", src_name);
2481 mainbin[src_id].id = src_id;
2482 mainbin[src_id].gst = src;
2484 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2485 "caps", caps, NULL);
2487 /* size of many video frames are larger than default blocksize as 4096 */
2488 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2489 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2491 if (player->media_stream_buffer_max_size[type] > 0)
2492 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2494 if (player->media_stream_buffer_min_percent[type] > 0)
2495 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2497 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2498 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2500 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2501 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2502 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2503 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2504 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2505 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2508 queue = gst_element_factory_make("queue2", queue_name);
2510 LOGE("failed to create %s", queue_name);
2513 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2515 mainbin[queue_id].id = queue_id;
2516 mainbin[queue_id].gst = queue;
2518 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2519 LOGE("failed to add src");
2523 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2524 LOGE("failed to add queue");
2528 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2529 LOGE("failed to link src and queue");
2533 /* create decoder */
2534 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2536 LOGE("failed to get srcpad of queue");
2540 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2541 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2543 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2544 LOGE("failed to create decoder");
2545 gst_object_unref(GST_OBJECT(srcpad));
2549 gst_object_unref(GST_OBJECT(srcpad));
2553 if (mainbin[src_id].gst) {
2554 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2555 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2556 gst_object_unref(mainbin[src_id].gst);
2557 mainbin[src_id].gst = NULL;
2560 if (mainbin[queue_id].gst) {
2561 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2562 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2563 gst_object_unref(mainbin[queue_id].gst);
2564 mainbin[queue_id].gst = NULL;
2571 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2573 GstPad *sinkpad = NULL;
2574 GstCaps *caps = NULL;
2575 GstElement *new_element = NULL;
2576 GstStructure *str = NULL;
2577 const gchar *name = NULL;
2579 mm_player_t *player = (mm_player_t*) data;
2583 MMPLAYER_RETURN_IF_FAIL(element && pad);
2584 MMPLAYER_RETURN_IF_FAIL(player &&
2586 player->pipeline->mainbin);
2588 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2589 * num_dynamic_pad will decreased after creating a sinkbin.
2591 player->num_dynamic_pad++;
2592 LOGD("stream count inc : %d", player->num_dynamic_pad);
2594 caps = gst_pad_query_caps(pad, NULL);
2595 MMPLAYER_CHECK_NULL(caps);
2597 str = gst_caps_get_structure (caps, 0);
2598 name = gst_structure_get_string(str, "media");
2600 LOGE("cannot get mimetype from structure.\n");
2604 if (strstr(name, "video")) {
2606 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2608 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2609 if (player->v_stream_caps) {
2610 gst_caps_unref(player->v_stream_caps);
2611 player->v_stream_caps = NULL;
2614 new_element = gst_element_factory_make("fakesink", NULL);
2615 player->num_dynamic_pad--;
2620 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2621 LOGE("failed to autoplug for caps");
2625 gst_caps_unref(caps);
2630 /* excute new_element if created*/
2632 LOGD("adding new element to pipeline\n");
2634 /* set state to READY before add to bin */
2635 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2637 /* add new element to the pipeline */
2638 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2639 LOGE("failed to add autoplug element to bin\n");
2643 /* get pad from element */
2644 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2646 LOGE("failed to get sinkpad from autoplug element\n");
2651 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2652 LOGE("failed to link autoplug element\n");
2656 gst_object_unref(sinkpad);
2659 /* run. setting PLAYING here since streamming source is live source */
2660 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2664 gst_caps_unref(caps);
2670 STATE_CHANGE_FAILED:
2672 /* FIXIT : take care if new_element has already added to pipeline */
2674 gst_object_unref(GST_OBJECT(new_element));
2677 gst_object_unref(GST_OBJECT(sinkpad));
2680 gst_caps_unref(caps);
2682 /* FIXIT : how to inform this error to MSL ????? */
2683 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2684 * then post an error to application
2689 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2691 mm_player_t* player = (mm_player_t*) data;
2695 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2696 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2697 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2698 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2700 * [1] audio and video will be dumped with filesink.
2701 * [2] autoplugging is done by just using pad caps.
2702 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2703 * and the video will be dumped via filesink.
2705 if (player->num_dynamic_pad == 0) {
2706 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2708 if (!__mmplayer_gst_remove_fakesink(player,
2709 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2710 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2711 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2712 * source element are not same. To overcome this situation, this function will called
2713 * several places and several times. Therefore, this is not an error case.
2718 /* create dot before error-return. for debugging */
2719 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2721 player->no_more_pad = TRUE;
2727 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2729 GstElement* element = NULL;
2730 gchar *user_agent = NULL;
2731 MMHandleType attrs = 0;
2734 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2736 /* get profile attribute */
2737 attrs = MMPLAYER_GET_ATTRS(player);
2739 LOGE("failed to get content attribute");
2743 element = gst_element_factory_make("rtspsrc", "rtsp source");
2745 LOGE("failed to create rtspsrc element");
2750 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2752 SECURE_LOGD("user_agent : %s", user_agent);
2754 /* setting property to streaming source */
2755 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2757 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2759 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2760 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2761 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2762 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2769 __mmplayer_gst_make_http_src(mm_player_t* player)
2771 GstElement* element = NULL;
2772 MMHandleType attrs = 0;
2773 gchar *user_agent, *cookies, **cookie_list;
2774 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2775 user_agent = cookies = NULL;
2779 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2781 /* get profile attribute */
2782 attrs = MMPLAYER_GET_ATTRS(player);
2784 LOGE("failed to get content attribute");
2788 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2790 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2792 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2797 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2798 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2800 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2801 http_timeout = player->ini.http_timeout;
2804 SECURE_LOGD("location : %s", player->profile.uri);
2805 SECURE_LOGD("cookies : %s", cookies);
2806 SECURE_LOGD("user_agent : %s", user_agent);
2807 LOGD("timeout : %d", http_timeout);
2809 /* setting property to streaming source */
2810 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2811 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2813 /* parsing cookies */
2814 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2815 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2816 g_strfreev(cookie_list);
2820 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2822 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2823 LOGW("[DASH] this is still experimental feature");
2830 __mmplayer_gst_make_file_src(mm_player_t* player)
2832 GstElement* element = NULL;
2835 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2837 LOGD("using filesrc for 'file://' handler");
2838 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2839 LOGE("failed to get storage info");
2843 element = gst_element_factory_make("filesrc", "source");
2845 LOGE("failed to create filesrc");
2849 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2855 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2857 mm_player_t *player = (mm_player_t *) data;
2859 g_return_val_if_fail(player, FALSE);
2860 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2862 gst_message_ref(msg);
2864 g_mutex_lock(&player->bus_msg_q_lock);
2865 g_queue_push_tail(player->bus_msg_q, msg);
2866 g_mutex_unlock(&player->bus_msg_q_lock);
2868 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2869 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2870 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2874 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2876 mm_player_t *player = (mm_player_t*)(data);
2877 GstMessage *msg = NULL;
2881 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2883 player->pipeline->mainbin &&
2884 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2887 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2889 LOGE("cannot get BUS from the pipeline");
2893 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2895 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2896 while (!player->bus_msg_thread_exit) {
2897 g_mutex_lock(&player->bus_msg_q_lock);
2898 msg = g_queue_pop_head(player->bus_msg_q);
2899 g_mutex_unlock(&player->bus_msg_q_lock);
2901 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2904 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2905 /* handle the gst msg */
2906 __mmplayer_gst_bus_msg_callback(msg, player);
2907 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2908 gst_message_unref(msg);
2911 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2912 gst_object_unref(GST_OBJECT(bus));
2919 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2921 gint64 dur_nsec = 0;
2924 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2926 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2927 return MM_ERROR_NONE;
2929 /* NOTE : duration cannot be zero except live streaming.
2930 * Since some element could have some timing problemn with quering duration, try again.
2932 if (player->duration == 0) {
2933 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2934 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2935 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2936 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2937 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2938 player->pending_seek.is_pending = TRUE;
2939 player->pending_seek.pos = position;
2940 player->seek_state = MMPLAYER_SEEK_NONE;
2941 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2942 return MM_ERROR_PLAYER_NO_OP;
2944 player->seek_state = MMPLAYER_SEEK_NONE;
2945 return MM_ERROR_PLAYER_SEEK;
2948 player->duration = dur_nsec;
2951 if (player->duration > 0 && player->duration < position) {
2952 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2953 return MM_ERROR_INVALID_ARGUMENT;
2957 return MM_ERROR_NONE;
2961 __mmplayer_gst_check_seekable(mm_player_t* player)
2963 GstQuery *query = NULL;
2964 gboolean seekable = FALSE;
2966 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2970 query = gst_query_new_seeking(GST_FORMAT_TIME);
2971 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2972 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2973 gst_query_unref(query);
2976 LOGW("non-seekable content");
2977 player->seek_state = MMPLAYER_SEEK_NONE;
2981 LOGW("failed to get seeking query");
2982 gst_query_unref(query); /* keep seeking operation */
2993 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2995 GstState element_state = GST_STATE_VOID_PENDING;
2996 GstState element_pending_state = GST_STATE_VOID_PENDING;
2997 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3001 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3002 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3004 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3007 ret = gst_element_set_state(element, state);
3009 if (ret == GST_STATE_CHANGE_FAILURE) {
3010 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3012 /* dump state of all element */
3013 __mmplayer_dump_pipeline_state(player);
3015 return MM_ERROR_PLAYER_INTERNAL;
3018 /* return here so state transition to be done in async mode */
3020 LOGD("async state transition. not waiting for state complete.\n");
3021 return MM_ERROR_NONE;
3024 /* wait for state transition */
3025 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3027 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3028 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3029 GST_ELEMENT_NAME(element),
3030 gst_element_state_get_name(state), timeout);
3032 LOGE(" [%s] state : %s pending : %s \n",
3033 GST_ELEMENT_NAME(element),
3034 gst_element_state_get_name(element_state),
3035 gst_element_state_get_name(element_pending_state));
3037 /* dump state of all element */
3038 __mmplayer_dump_pipeline_state(player);
3040 return MM_ERROR_PLAYER_INTERNAL;
3043 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3047 return MM_ERROR_NONE;
3050 int __mmplayer_gst_start(mm_player_t* player)
3052 int ret = MM_ERROR_NONE;
3053 gboolean async = FALSE;
3057 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3059 /* NOTE : if SetPosition was called before Start. do it now */
3060 /* streaming doesn't support it. so it should be always sync */
3061 /* !!create one more api to check if there is pending seek rather than checking variables */
3062 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3063 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3064 ret = __mmplayer_gst_pause(player, FALSE);
3065 if (ret != MM_ERROR_NONE) {
3066 LOGE("failed to set state to PAUSED for pending seek");
3070 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3071 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3072 LOGW("failed to seek pending postion. starting from the begin of content");
3075 LOGD("current state before doing transition");
3076 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3077 MMPLAYER_PRINT_STATE(player);
3079 /* set pipeline state to PLAYING */
3080 ret = __mmplayer_gst_set_state(player,
3081 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3083 if (ret == MM_ERROR_NONE) {
3084 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3086 LOGE("failed to set state to PLAYING");
3090 /* generating debug info before returning error */
3091 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3098 int __mmplayer_gst_stop(mm_player_t* player)
3100 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3101 MMHandleType attrs = 0;
3102 gboolean rewind = FALSE;
3104 int ret = MM_ERROR_NONE;
3108 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3109 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3111 LOGD("current state before doing transition");
3112 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3113 MMPLAYER_PRINT_STATE(player);
3115 attrs = MMPLAYER_GET_ATTRS(player);
3117 LOGE("cannot get content attribute\n");
3118 return MM_ERROR_PLAYER_INTERNAL;
3121 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3122 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3124 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3125 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3128 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3129 /* disable the async state transition because there could be no data in the pipeline */
3130 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3134 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3136 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3137 /* enable the async state transition as default operation */
3138 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3141 /* return if set_state has failed */
3142 if (ret != MM_ERROR_NONE) {
3143 LOGE("failed to set state.\n");
3149 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3150 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3151 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3152 LOGW("failed to rewind\n");
3153 ret = MM_ERROR_PLAYER_SEEK;
3158 player->sent_bos = FALSE;
3160 if (player->es_player_push_mode) //for cloudgame
3163 /* wait for seek to complete */
3164 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3165 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3166 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3168 LOGE("fail to stop player.\n");
3169 ret = MM_ERROR_PLAYER_INTERNAL;
3170 __mmplayer_dump_pipeline_state(player);
3173 /* generate dot file if enabled */
3174 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3181 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3183 int ret = MM_ERROR_NONE;
3187 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3188 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3190 LOGD("current state before doing transition");
3191 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3192 MMPLAYER_PRINT_STATE(player);
3194 /* set pipeline status to PAUSED */
3195 ret = __mmplayer_gst_set_state(player,
3196 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3198 if (FALSE == async) {
3199 if (ret != MM_ERROR_NONE) {
3200 GstMessage *msg = NULL;
3201 GTimer *timer = NULL;
3202 gdouble MAX_TIMEOUT_SEC = 3;
3204 LOGE("failed to set state to PAUSED");
3206 if (!player->bus_watcher) {
3207 LOGE("there is no bus msg thread. pipeline is shutting down.");
3211 if (player->msg_posted) {
3212 LOGE("error msg is already posted.");
3216 timer = g_timer_new();
3217 g_timer_start(timer);
3219 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3222 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3224 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3225 GError *error = NULL;
3227 /* parse error code */
3228 gst_message_parse_error(msg, &error, NULL);
3230 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3231 /* Note : the streaming error from the streaming source is handled
3232 * using __mmplayer_handle_streaming_error.
3234 __mmplayer_handle_streaming_error(player, msg);
3237 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3239 if (error->domain == GST_STREAM_ERROR)
3240 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3241 else if (error->domain == GST_RESOURCE_ERROR)
3242 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3243 else if (error->domain == GST_LIBRARY_ERROR)
3244 ret = __mmplayer_gst_handle_library_error(player, error->code);
3245 else if (error->domain == GST_CORE_ERROR)
3246 ret = __mmplayer_gst_handle_core_error(player, error->code);
3248 g_error_free(error);
3250 player->msg_posted = TRUE;
3252 gst_message_unref(msg);
3254 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3256 gst_object_unref(bus);
3257 g_timer_stop(timer);
3258 g_timer_destroy(timer);
3262 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3263 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3265 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3268 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3272 /* generate dot file before returning error */
3273 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3280 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3282 int ret = MM_ERROR_NONE;
3287 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3288 MM_ERROR_PLAYER_NOT_INITIALIZED);
3290 LOGD("current state before doing transition");
3291 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3292 MMPLAYER_PRINT_STATE(player);
3295 LOGD("do async state transition to PLAYING");
3297 /* set pipeline state to PLAYING */
3298 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3300 ret = __mmplayer_gst_set_state(player,
3301 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3302 if (ret != MM_ERROR_NONE) {
3303 LOGE("failed to set state to PLAYING");
3307 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3311 /* generate dot file */
3312 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3319 /* sending event to one of sinkelements */
3321 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3323 GstEvent * event2 = NULL;
3324 GList *sinks = NULL;
3325 gboolean res = FALSE;
3328 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3329 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3331 /* While adding subtitles in live feeds seek is getting called.
3332 Adding defensive check in framework layer.*/
3333 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3334 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3335 LOGE("Should not send seek event during live playback");
3340 if (player->play_subtitle)
3341 event2 = gst_event_copy((const GstEvent *)event);
3343 sinks = player->sink_elements;
3345 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3347 if (GST_IS_ELEMENT(sink)) {
3348 /* keep ref to the event */
3349 gst_event_ref(event);
3351 if ((res = gst_element_send_event(sink, event))) {
3352 LOGD("sending event[%s] to sink element [%s] success!\n",
3353 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3355 /* rtsp case, asyn_done is not called after seek during pause state */
3356 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3357 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3358 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3359 LOGD("RTSP seek completed, after pause state..\n");
3360 player->seek_state = MMPLAYER_SEEK_NONE;
3361 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3367 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3368 sinks = g_list_next(sinks);
3375 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3376 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3379 sinks = g_list_next(sinks);
3382 /* Note : Textbin is not linked to the video or audio bin.
3383 * It needs to send the event to the text sink seperatelly.
3385 if (player->play_subtitle && player->pipeline) {
3386 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3388 if (GST_IS_ELEMENT(text_sink)) {
3389 /* keep ref to the event */
3390 gst_event_ref(event2);
3392 if ((res = gst_element_send_event(text_sink, event2)))
3393 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3394 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3396 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3397 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3399 gst_event_unref(event2);
3403 gst_event_unref(event);
3411 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3412 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3413 gint64 cur, GstSeekType stop_type, gint64 stop)
3415 GstEvent* event = NULL;
3416 gboolean result = FALSE;
3420 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3422 if (player->pipeline && player->pipeline->textbin)
3423 __mmplayer_drop_subtitle(player, FALSE);
3425 event = gst_event_new_seek(rate, format, flags, cur_type,
3426 cur, stop_type, stop);
3428 result = __mmplayer_gst_send_event_to_sink(player, event);
3436 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3438 int ret = MM_ERROR_NONE;
3439 gint64 pos_nsec = 0;
3440 gboolean accurated = FALSE;
3441 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3445 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3447 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3448 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3451 ret = __mmplayer_gst_check_duration(player, position);
3452 if (ret != MM_ERROR_NONE) {
3453 LOGE("failed to check duration 0x%X", ret);
3454 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3457 if (!__mmplayer_gst_check_seekable(player))
3458 return MM_ERROR_PLAYER_NO_OP;
3460 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3461 position, player->playback_rate, player->duration);
3463 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3464 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3465 This causes problem is position calculation during normal pause resume scenarios also.
3466 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3467 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3468 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3469 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3470 LOGW("getting current position failed in seek");
3472 player->last_position = pos_nsec;
3473 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3476 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3477 LOGD("not completed seek");
3478 return MM_ERROR_PLAYER_DOING_SEEK;
3481 if (!internal_called)
3482 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3484 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3485 that's why set position through property. */
3486 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3487 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3488 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3489 (!player->videodec_linked) && (!player->audiodec_linked)) {
3491 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3492 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3494 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3495 player->seek_state = MMPLAYER_SEEK_NONE;
3496 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3498 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3500 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3502 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3504 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3505 GST_FORMAT_TIME, seek_flags,
3506 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3507 LOGE("failed to set position");
3512 /* NOTE : store last seeking point to overcome some bad operation
3513 * (returning zero when getting current position) of some elements
3515 player->last_position = position;
3517 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3518 if (player->playback_rate > 1.0)
3519 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3521 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3522 LOGD("buffering should be reset after seeking");
3523 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3524 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3528 return MM_ERROR_NONE;
3531 player->pending_seek.is_pending = TRUE;
3532 player->pending_seek.pos = position;
3534 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3535 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3536 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3537 player->pending_seek.pos);
3539 return MM_ERROR_NONE;
3542 player->seek_state = MMPLAYER_SEEK_NONE;
3543 return MM_ERROR_PLAYER_SEEK;
3547 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3549 #define TRICKPLAY_OFFSET GST_MSECOND
3551 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3552 gint64 pos_nsec = 0;
3553 gboolean ret = TRUE;
3555 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3556 MM_ERROR_PLAYER_NOT_INITIALIZED);
3558 current_state = MMPLAYER_CURRENT_STATE(player);
3560 /* NOTE : query position except paused state to overcome some bad operation
3561 * please refer to below comments in details
3563 if (current_state != MM_PLAYER_STATE_PAUSED)
3564 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3566 /* NOTE : get last point to overcome some bad operation of some elements
3567 *(returning zero when getting current position in paused state
3568 * and when failed to get postion during seeking
3570 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3571 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3573 if (player->playback_rate < 0.0)
3574 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3576 pos_nsec = player->last_position;
3579 pos_nsec = player->last_position;
3581 player->last_position = pos_nsec;
3583 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3586 if (player->duration > 0 && pos_nsec > player->duration)
3587 pos_nsec = player->duration;
3589 player->last_position = pos_nsec;
3592 *position = pos_nsec;
3594 return MM_ERROR_NONE;
3597 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3599 #define STREAMING_IS_FINISHED 0
3600 #define BUFFERING_MAX_PER 100
3601 #define DEFAULT_PER_VALUE -1
3602 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3604 MMPlayerGstElement *mainbin = NULL;
3605 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3606 gint64 buffered_total = 0;
3607 gint64 position = 0;
3608 gint buffered_sec = -1;
3609 GstBufferingMode mode = GST_BUFFERING_STREAM;
3610 gint64 content_size_time = player->duration;
3611 guint64 content_size_bytes = player->http_content_size;
3613 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3615 player->pipeline->mainbin,
3616 MM_ERROR_PLAYER_NOT_INITIALIZED);
3618 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3623 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3624 /* and rtsp is not ready yet. */
3625 LOGW("it's only used for http streaming case");
3626 return MM_ERROR_PLAYER_NO_OP;
3629 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3630 LOGW("Time format is not supported yet");
3631 return MM_ERROR_INVALID_ARGUMENT;
3634 if (content_size_time <= 0 || content_size_bytes <= 0) {
3635 LOGW("there is no content size");
3636 return MM_ERROR_NONE;
3639 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3640 LOGW("fail to get current position");
3641 return MM_ERROR_NONE;
3644 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3645 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3647 mainbin = player->pipeline->mainbin;
3648 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3650 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3651 GstQuery *query = NULL;
3652 gint byte_in_rate = 0, byte_out_rate = 0;
3653 gint64 estimated_total = 0;
3655 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3656 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3657 LOGW("fail to get buffering query from queue2");
3659 gst_query_unref(query);
3660 return MM_ERROR_NONE;
3663 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3664 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3666 if (mode == GST_BUFFERING_STREAM) {
3667 /* using only queue in case of push mode(ts / mp3) */
3668 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3669 GST_FORMAT_BYTES, &buffered_total)) {
3670 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3671 stop_per = 100 * buffered_total / content_size_bytes;
3674 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3676 guint num_of_ranges = 0;
3677 gint64 start_byte = 0, stop_byte = 0;
3679 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3680 if (estimated_total != STREAMING_IS_FINISHED) {
3681 /* buffered size info from queue2 */
3682 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3683 for (idx = 0; idx < num_of_ranges; idx++) {
3684 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3685 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3687 buffered_total += (stop_byte - start_byte);
3690 stop_per = BUFFERING_MAX_PER;
3692 gst_query_unref(query);
3695 if (stop_per == DEFAULT_PER_VALUE) {
3696 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3698 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3700 /* buffered size info from multiqueue */
3701 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3702 guint curr_size_bytes = 0;
3703 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3704 "curr-size-bytes", &curr_size_bytes, NULL);
3705 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3706 buffered_total += curr_size_bytes;
3709 if (avg_byterate > 0)
3710 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3711 else if (player->total_maximum_bitrate > 0)
3712 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3713 else if (player->total_bitrate > 0)
3714 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3716 if (buffered_sec >= 0)
3717 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3721 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3722 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3724 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3725 buffered_total, buffered_sec, *start_pos, *stop_pos);
3727 return MM_ERROR_NONE;
3730 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3732 GstElement* element = NULL;
3735 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3736 player->pipeline->mainbin, NULL);
3738 /* setup source for gapless play */
3739 switch (player->profile.uri_type) {
3741 case MM_PLAYER_URI_TYPE_FILE:
3742 element = __mmplayer_gst_make_file_src(player);
3744 case MM_PLAYER_URI_TYPE_URL_HTTP:
3745 element = __mmplayer_gst_make_http_src(player);
3748 LOGE("not support uri type %d", player->profile.uri_type);
3753 LOGE("failed to create source element");
3761 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3763 MMHandleType attrs = 0;
3766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3767 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3769 /* get profile attribute */
3770 attrs = MMPLAYER_GET_ATTRS(player);
3772 LOGE("failed to get content attribute");
3773 return MM_ERROR_PLAYER_INTERNAL;
3776 SECURE_LOGD("uri : %s", player->profile.uri);
3778 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3779 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3780 LOGE("failed to commit");
3782 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3783 return MM_ERROR_PLAYER_INTERNAL;
3785 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3786 return MM_ERROR_PLAYER_INTERNAL;
3788 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3789 return MM_ERROR_PLAYER_INTERNAL;
3792 return MM_ERROR_NONE;
3795 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3797 MMPlayerGstElement *mainbin = NULL;
3798 GstElement *pd_src = NULL;
3799 GstElement *pd_queue = NULL;
3800 GstElement *pd_decodebin = NULL;
3801 GList* element_bucket = NULL;
3802 MMHandleType attrs = 0;
3804 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3807 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3808 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3810 /* get profile attribute */
3811 attrs = MMPLAYER_GET_ATTRS(player);
3813 LOGE("failed to get content attribute");
3814 return MM_ERROR_PLAYER_INTERNAL;
3817 LOGD("http playback with progressive download : %d", player->pd_mode);
3819 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3820 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3821 MMPLAYER_FREEIF(player->pd_file_save_path);
3823 SECURE_LOGD("PD Location : %s", path);
3825 LOGE("filed to find pd location");
3826 return MM_ERROR_PLAYER_INTERNAL;
3829 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3830 LOGE("failed to get storage info");
3831 return MM_ERROR_PLAYER_INTERNAL;
3833 player->pd_file_save_path = g_strdup(path);
3836 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3838 LOGE("failed to create PD push source");
3839 return MM_ERROR_PLAYER_INTERNAL;
3842 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3843 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3845 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3847 mainbin = player->pipeline->mainbin;
3849 /* take source element */
3850 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3851 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3852 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3855 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3856 pd_queue = gst_element_factory_make("queue2", "queue2");
3858 LOGE("failed to create pd buffer element");
3863 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3864 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3865 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3867 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3869 player->streamer->is_pd_mode = TRUE;
3871 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3872 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3873 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3875 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3876 if (!pd_decodebin) {
3877 LOGE("failed to create decodebin");
3881 /* default size of mq in decodebin is 2M
3882 * but it can cause blocking issue during seeking depends on content. */
3883 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3885 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3886 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3888 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3890 /* add elements to pipeline */
3891 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3892 LOGE("failed to add elements to pipeline");
3896 /* linking elements in the bucket by added order. */
3897 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3898 LOGE("failed to link some elements");
3902 g_list_free(element_bucket);
3905 return MM_ERROR_NONE;
3908 MMPLAYER_FREEIF(player->pd_file_save_path);
3909 g_list_free(element_bucket);
3911 if (mainbin[MMPLAYER_M_SRC].gst)
3912 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3914 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3915 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3917 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3918 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3920 mainbin[MMPLAYER_M_SRC].gst = NULL;
3921 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3922 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3924 return MM_ERROR_PLAYER_INTERNAL;
3927 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3929 MMPlayerGstElement *mainbin = NULL;
3930 GstElement* src_elem = NULL;
3931 GstElement *autoplug_elem = NULL;
3932 GList* element_bucket = NULL;
3933 MMHandleType attrs = 0;
3934 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3937 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3938 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3940 /* get profile attribute */
3941 attrs = MMPLAYER_GET_ATTRS(player);
3943 LOGE("failed to get content attribute");
3944 return MM_ERROR_PLAYER_INTERNAL;
3947 LOGD("uri type %d", player->profile.uri_type);
3949 /* create source element */
3950 switch (player->profile.uri_type) {
3951 case MM_PLAYER_URI_TYPE_URL_RTSP:
3952 src_elem = __mmplayer_gst_make_rtsp_src(player);
3954 case MM_PLAYER_URI_TYPE_URL_HTTP:
3955 src_elem = __mmplayer_gst_make_http_src(player);
3957 case MM_PLAYER_URI_TYPE_FILE:
3958 src_elem = __mmplayer_gst_make_file_src(player);
3960 case MM_PLAYER_URI_TYPE_SS:
3962 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3963 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3965 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3969 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3970 LOGD("get timeout from ini");
3971 http_timeout = player->ini.http_timeout;
3974 /* setting property to streaming source */
3975 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3978 case MM_PLAYER_URI_TYPE_MEM:
3980 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3982 src_elem = gst_element_factory_make("appsrc", "mem-source");
3984 LOGE("failed to create appsrc element");
3988 g_object_set(src_elem, "stream-type", stream_type,
3989 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3991 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3992 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3993 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3994 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3998 LOGE("not support uri type");
4003 LOGE("failed to create source element");
4004 return MM_ERROR_PLAYER_INTERNAL;
4007 mainbin = player->pipeline->mainbin;
4009 /* take source element */
4010 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4012 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4013 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4014 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4016 /* create next element for auto-plugging */
4017 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4018 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4019 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4020 if (!autoplug_elem) {
4021 LOGE("failed to create typefind element");
4025 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4026 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4027 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4028 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4029 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4030 if (!autoplug_elem) {
4031 LOGE("failed to create decodebin");
4035 /* default size of mq in decodebin is 2M
4036 * but it can cause blocking issue during seeking depends on content. */
4037 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4040 if (autoplug_elem) {
4041 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4042 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4043 mainbin[autoplug_elem_id].gst = autoplug_elem;
4045 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4048 /* add elements to pipeline */
4049 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4050 LOGE("failed to add elements to pipeline");
4054 /* linking elements in the bucket by added order. */
4055 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4056 LOGE("failed to link some elements");
4060 /* FIXME: need to check whether this is required or not. */
4061 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4062 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4063 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4064 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4066 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4067 LOGE("failed to create fakesink");
4070 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4072 /* take ownership of fakesink. we are reusing it */
4073 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4075 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4076 LOGE("failed to add fakesink to bin");
4077 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4082 g_list_free(element_bucket);
4085 return MM_ERROR_NONE;
4088 g_list_free(element_bucket);
4090 if (mainbin[MMPLAYER_M_SRC].gst)
4091 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4093 if (mainbin[autoplug_elem_id].gst)
4094 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4096 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4097 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4099 mainbin[MMPLAYER_M_SRC].gst = NULL;
4100 mainbin[autoplug_elem_id].gst = NULL;
4101 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4103 return MM_ERROR_PLAYER_INTERNAL;
4106 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4109 MMPlayerGstElement *mainbin = NULL;
4112 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4113 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4115 mainbin = player->pipeline->mainbin;
4117 /* connect bus callback */
4118 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4120 LOGE("cannot get bus from pipeline");
4121 return MM_ERROR_PLAYER_INTERNAL;
4124 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4125 player->context.thread_default = g_main_context_get_thread_default();
4126 if (player->context.thread_default == NULL) {
4127 player->context.thread_default = g_main_context_default();
4128 LOGD("thread-default context is the global default context");
4130 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4132 /* set sync handler to get tag synchronously */
4133 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4134 gst_object_unref(GST_OBJECT(bus));
4136 /* create gst bus_msb_cb thread */
4137 g_mutex_init(&player->bus_msg_thread_mutex);
4138 g_cond_init(&player->bus_msg_thread_cond);
4139 player->bus_msg_thread_exit = FALSE;
4140 player->bus_msg_thread =
4141 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4142 if (!player->bus_msg_thread) {
4143 LOGE("failed to create gst BUS msg thread");
4144 g_mutex_clear(&player->bus_msg_thread_mutex);
4145 g_cond_clear(&player->bus_msg_thread_cond);
4146 return MM_ERROR_PLAYER_INTERNAL;
4150 return MM_ERROR_NONE;