4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
87 __mmplayer_check_error_posted_from_activated_track(mm_player_t *player, gchar *src_element_name)
89 /* check whether the error is posted from not-activated track or not */
91 gint active_pad_index = 0;
93 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
95 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
96 LOGD("current active pad index -%d", active_pad_index);
98 if (src_element_name) {
101 if (player->audio_decoders) {
102 GList *adec = player->audio_decoders;
103 for (; adec ; adec = g_list_next(adec)) {
104 gchar *name = adec->data;
106 LOGD("found audio decoder name = %s", name);
107 if (g_strrstr(name, src_element_name)) {
114 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
117 if (active_pad_index != msg_src_pos) {
118 LOGD("skip error because error is posted from no activated track");
126 __mmplayer_gst_transform_error_decode(mm_player_t *player, const char *klass)
128 /* Demuxer can't parse one track because it's corrupted.
129 * So, the decoder for it is not linked.
130 * But, it has one playable track.
132 if (g_strrstr(klass, "Demux")) {
133 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
134 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
135 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
136 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
138 if (player->pipeline->audiobin) { // PCM
139 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
141 LOGD("not found any available codec. Player should be destroyed.\n");
142 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
147 return MM_ERROR_PLAYER_INVALID_STREAM;
151 __mmplayer_gst_transform_error_type(mm_player_t *player, GstElement *src_element)
153 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
154 LOGE("Not supported subtitle.");
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
157 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
161 __mmplayer_gst_transform_error_failed(mm_player_t *player, const char *klass, GError *error)
163 /* Decoder Custom Message */
164 if (!strstr(error->message, "ongoing"))
165 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
167 if (strncasecmp(klass, "audio", 5)) {
168 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
169 LOGD("Video can keep playing.\n");
170 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
172 } else if (strncasecmp(klass, "video", 5)) {
173 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
174 LOGD("Audio can keep playing.\n");
175 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
179 LOGD("not found any available codec. Player should be destroyed.\n");
180 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
184 __mmplayer_gst_transform_error_decrypt(mm_player_t *player, GError *error)
186 if (strstr(error->message, "rights expired"))
187 return MM_ERROR_PLAYER_DRM_EXPIRED;
188 else if (strstr(error->message, "no rights"))
189 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
190 else if (strstr(error->message, "has future rights"))
191 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
192 else if (strstr(error->message, "opl violation"))
193 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
195 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
197 /* NOTE : decide gstreamer state whether there is some playable track or not. */
199 __mmplayer_gst_transform_gsterror(mm_player_t *player, GstMessage *message, GError *error)
201 gchar *src_element_name = NULL;
202 GstElement *src_element = NULL;
203 GstElementFactory *factory = NULL;
204 const gchar *klass = NULL;
208 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
209 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
211 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
213 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
215 src_element = GST_ELEMENT_CAST(message->src);
217 return MM_ERROR_PLAYER_INTERNAL;
219 src_element_name = GST_ELEMENT_NAME(src_element);
220 if (!src_element_name)
221 return MM_ERROR_PLAYER_INTERNAL;
223 factory = gst_element_get_factory(src_element);
225 return MM_ERROR_PLAYER_INTERNAL;
227 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
229 return MM_ERROR_PLAYER_INTERNAL;
231 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
232 error->code, error->message, src_element_name, klass);
234 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
235 return MM_ERROR_NONE;
237 switch (error->code) {
238 case GST_STREAM_ERROR_DECODE:
239 return __mmplayer_gst_transform_error_decode(player, klass);
240 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
241 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
242 case GST_STREAM_ERROR_WRONG_TYPE:
243 return __mmplayer_gst_transform_error_type(player, src_element);
244 case GST_STREAM_ERROR_FAILED:
245 return __mmplayer_gst_transform_error_failed(player, klass, error);
246 case GST_STREAM_ERROR_DECRYPT:
247 case GST_STREAM_ERROR_DECRYPT_NOKEY:
248 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
249 return __mmplayer_gst_transform_error_decrypt(player, error);
256 return MM_ERROR_PLAYER_INVALID_STREAM;
260 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
262 gint trans_err = MM_ERROR_NONE;
266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
269 case GST_CORE_ERROR_MISSING_PLUGIN:
270 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
271 case GST_CORE_ERROR_STATE_CHANGE:
272 case GST_CORE_ERROR_SEEK:
273 case GST_CORE_ERROR_NOT_IMPLEMENTED:
274 case GST_CORE_ERROR_FAILED:
275 case GST_CORE_ERROR_TOO_LAZY:
276 case GST_CORE_ERROR_PAD:
277 case GST_CORE_ERROR_THREAD:
278 case GST_CORE_ERROR_NEGOTIATION:
279 case GST_CORE_ERROR_EVENT:
280 case GST_CORE_ERROR_CAPS:
281 case GST_CORE_ERROR_TAG:
282 case GST_CORE_ERROR_CLOCK:
283 case GST_CORE_ERROR_DISABLED:
285 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
295 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
297 gint trans_err = MM_ERROR_NONE;
301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
304 case GST_LIBRARY_ERROR_FAILED:
305 case GST_LIBRARY_ERROR_TOO_LAZY:
306 case GST_LIBRARY_ERROR_INIT:
307 case GST_LIBRARY_ERROR_SHUTDOWN:
308 case GST_LIBRARY_ERROR_SETTINGS:
309 case GST_LIBRARY_ERROR_ENCODE:
311 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
321 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
323 gint trans_err = MM_ERROR_NONE;
327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
330 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
331 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
333 case GST_RESOURCE_ERROR_NOT_FOUND:
334 case GST_RESOURCE_ERROR_OPEN_READ:
335 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
336 || MMPLAYER_IS_RTSP_STREAMING(player)) {
337 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
340 case GST_RESOURCE_ERROR_READ:
341 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
342 || MMPLAYER_IS_RTSP_STREAMING(player)) {
343 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
345 } else if (message != NULL && message->src != NULL) {
346 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
347 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
349 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
350 path_type = MMPLAYER_PATH_VOD;
351 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
352 path_type = MMPLAYER_PATH_TEXT;
354 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
355 /* check storage state */
356 storage_get_state(player->storage_info[path_type].id, &storage_state);
357 player->storage_info[path_type].state = storage_state;
358 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
361 case GST_RESOURCE_ERROR_WRITE:
362 case GST_RESOURCE_ERROR_FAILED:
363 case GST_RESOURCE_ERROR_SEEK:
364 case GST_RESOURCE_ERROR_TOO_LAZY:
365 case GST_RESOURCE_ERROR_BUSY:
366 case GST_RESOURCE_ERROR_OPEN_WRITE:
367 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
368 case GST_RESOURCE_ERROR_CLOSE:
369 case GST_RESOURCE_ERROR_SYNC:
370 case GST_RESOURCE_ERROR_SETTINGS:
372 trans_err = MM_ERROR_PLAYER_INTERNAL;
382 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
384 gint trans_err = MM_ERROR_NONE;
388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
389 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
390 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
392 switch (error->code) {
393 case GST_STREAM_ERROR_FAILED:
394 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
395 case GST_STREAM_ERROR_DECODE:
396 case GST_STREAM_ERROR_WRONG_TYPE:
397 case GST_STREAM_ERROR_DECRYPT:
398 case GST_STREAM_ERROR_DECRYPT_NOKEY:
399 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
400 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
403 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
404 case GST_STREAM_ERROR_TOO_LAZY:
405 case GST_STREAM_ERROR_ENCODE:
406 case GST_STREAM_ERROR_DEMUX:
407 case GST_STREAM_ERROR_MUX:
408 case GST_STREAM_ERROR_FORMAT:
410 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
420 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
422 MMMessageParamType msg_param;
423 gchar *msg_src_element;
427 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
428 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
430 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
432 memset(&msg_param, 0, sizeof(MMMessageParamType));
434 if (error->domain == GST_CORE_ERROR) {
435 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
436 } else if (error->domain == GST_LIBRARY_ERROR) {
437 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
438 } else if (error->domain == GST_RESOURCE_ERROR) {
439 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
440 } else if (error->domain == GST_STREAM_ERROR) {
441 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
443 LOGW("This error domain is not defined.\n");
445 /* we treat system error as an internal error */
446 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
450 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
452 msg_param.data = (void *) error->message;
454 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
455 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
459 if (msg_param.code == MM_ERROR_NONE)
462 /* skip error to avoid duplicated posting */
463 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
464 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
465 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
466 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
468 /* The error will be handled by mused.
469 * @ref _mmplayer_manage_external_storage_state() */
471 LOGW("storage is removed, skip error post");
475 /* post error to application */
476 if (!player->msg_posted) {
477 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
478 /* don't post more if one was sent already */
479 player->msg_posted = TRUE;
481 LOGD("skip error post because it's sent already.\n");
489 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
492 MMMessageParamType msg_param;
493 gchar *msg_src_element = NULL;
494 GstStructure *s = NULL;
496 gchar *error_string = NULL;
500 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
501 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
503 s = gst_structure_copy(gst_message_get_structure(message));
506 if (!gst_structure_get_uint(s, "error_id", &error_id))
507 error_id = MMPLAYER_STREAMING_ERROR_NONE;
510 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
513 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
516 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
519 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
522 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
525 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
528 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
531 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
534 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
537 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
540 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
543 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
546 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
549 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
552 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
555 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
558 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
561 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
564 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
567 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
570 case MMPLAYER_STREAMING_ERROR_GONE:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
573 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
576 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
579 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
582 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
585 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
588 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
591 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
594 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
597 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
600 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
603 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
606 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
607 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
609 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
610 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
612 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
613 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
615 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
616 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
618 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
619 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
621 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
622 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
624 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
625 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
627 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
628 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
630 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
631 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
633 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
634 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
636 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
637 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
639 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
640 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
642 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
643 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
647 gst_structure_free(s);
648 return MM_ERROR_PLAYER_STREAMING_FAIL;
652 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
654 msg_param.data = (void *) error_string;
657 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
659 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
660 msg_src_element, msg_param.code, (char*)msg_param.data);
663 /* post error to application */
664 if (!player->msg_posted) {
665 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
667 /* don't post more if one was sent already */
668 player->msg_posted = TRUE;
670 LOGD("skip error post because it's sent already.\n");
672 gst_structure_free(s);
673 g_free(error_string);
681 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
683 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
684 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
685 gst_tag_list_get_string(tags, "stitching_software",
686 &metadata->stitching_software);
687 gst_tag_list_get_string(tags, "projection_type",
688 &metadata->projection_type_string);
689 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
690 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
691 gst_tag_list_get_int(tags, "init_view_heading",
692 &metadata->init_view_heading);
693 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
694 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
695 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
696 gst_tag_list_get_int(tags, "full_pano_width_pixels",
697 &metadata->full_pano_width_pixels);
698 gst_tag_list_get_int(tags, "full_pano_height_pixels",
699 &metadata->full_pano_height_pixels);
700 gst_tag_list_get_int(tags, "cropped_area_image_width",
701 &metadata->cropped_area_image_width);
702 gst_tag_list_get_int(tags, "cropped_area_image_height",
703 &metadata->cropped_area_image_height);
704 gst_tag_list_get_int(tags, "cropped_area_left",
705 &metadata->cropped_area_left);
706 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
707 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
708 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
709 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
713 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
716 /* macro for better code readability */
717 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
718 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
719 if (string != NULL) { \
720 SECURE_LOGD("update tag string : %s\n", string); \
721 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
722 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
723 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
724 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
725 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
726 MMPLAYER_FREEIF(new_string); \
728 mm_attrs_set_string_by_name(attribute, playertag, string); \
730 MMPLAYER_FREEIF(string); \
734 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
736 GstSample *sample = NULL;\
737 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
738 GstMapInfo info = GST_MAP_INFO_INIT;\
739 buffer = gst_sample_get_buffer(sample);\
740 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
741 LOGD("failed to get image data from tag");\
742 gst_sample_unref(sample);\
745 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
746 MMPLAYER_FREEIF(player->album_art);\
747 player->album_art = (gchar *)g_malloc(info.size);\
748 if (player->album_art) {\
749 memcpy(player->album_art, info.data, info.size);\
750 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
751 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
752 msg_param.data = (void *)player->album_art;\
753 msg_param.size = info.size;\
754 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
755 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
758 gst_buffer_unmap(buffer, &info);\
759 gst_sample_unref(sample);\
763 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
765 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
768 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
769 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
770 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
771 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
772 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
774 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
775 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
776 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
777 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
778 player->bitrate[track_type] = v_uint; \
779 player->total_bitrate = 0; \
780 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
781 player->total_bitrate += player->bitrate[i]; \
782 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
783 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
784 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
785 player->maximum_bitrate[track_type] = v_uint; \
786 player->total_maximum_bitrate = 0; \
787 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
788 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
789 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
790 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
792 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
799 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
800 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
802 string = g_strdup_printf("%d", g_date_get_year(date));\
803 mm_attrs_set_string_by_name(attribute, playertag, string);\
804 SECURE_LOGD("metainfo year : %s\n", string);\
805 MMPLAYER_FREEIF(string);\
810 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
811 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
812 if (datetime != NULL) {\
813 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
814 mm_attrs_set_string_by_name(attribute, playertag, string);\
815 SECURE_LOGD("metainfo year : %s\n", string);\
816 MMPLAYER_FREEIF(string);\
817 gst_date_time_unref(datetime);\
821 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
822 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
824 /* FIXIT : don't know how to store date */\
830 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
831 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
833 /* FIXIT : don't know how to store date */\
840 GstTagList* tag_list = NULL;
842 MMHandleType attrs = 0;
847 GstDateTime *datetime = NULL;
849 GstBuffer *buffer = NULL;
851 MMMessageParamType msg_param = {0, };
853 /* currently not used. but those are needed for above macro */
854 //guint64 v_uint64 = 0;
855 //gdouble v_double = 0;
857 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
859 attrs = MMPLAYER_GET_ATTRS(player);
861 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
863 /* get tag list from gst message */
864 gst_message_parse_tag(msg, &tag_list);
866 /* store tags to player attributes */
867 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
868 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
869 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
870 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
871 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
872 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
874 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
875 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
876 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
877 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
878 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
879 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
880 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
886 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
887 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
888 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
889 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
892 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
896 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
898 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
899 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
900 MMPLAYER_UPDATE_TAG_LOCK(player);
901 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
902 MMPLAYER_UPDATE_TAG_UNLOCK(player);
903 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
904 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
905 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
907 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
909 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
910 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
911 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
912 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
913 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
914 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
915 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
917 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
918 if (player->video360_metadata.is_spherical == -1) {
919 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
920 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
921 player->video360_metadata.is_spherical);
922 if (player->video360_metadata.is_spherical == 1) {
923 LOGD("This is spherical content for 360 playback.");
924 player->is_content_spherical = TRUE;
926 LOGD("This is not spherical content");
927 player->is_content_spherical = FALSE;
930 if (player->video360_metadata.projection_type_string) {
931 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
932 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
934 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
935 player->is_content_spherical = player->is_video360_enabled = FALSE;
939 if (player->video360_metadata.stereo_mode_string) {
940 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
941 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
942 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
943 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
944 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
945 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
947 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
948 player->is_content_spherical = player->is_video360_enabled = FALSE;
954 if (mm_attrs_commit_all(attrs))
955 LOGE("failed to commit.\n");
957 gst_tag_list_unref(tag_list);
962 /* if retval is FALSE, it will be dropped for perfomance. */
964 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
966 gboolean retval = FALSE;
968 if (!(player->pipeline && player->pipeline->mainbin)) {
969 LOGE("player pipeline handle is null");
973 switch (GST_MESSAGE_TYPE(message)) {
974 case GST_MESSAGE_TAG:
975 case GST_MESSAGE_EOS:
976 case GST_MESSAGE_ERROR:
977 case GST_MESSAGE_WARNING:
978 case GST_MESSAGE_CLOCK_LOST:
979 case GST_MESSAGE_NEW_CLOCK:
980 case GST_MESSAGE_ELEMENT:
981 case GST_MESSAGE_DURATION_CHANGED:
982 case GST_MESSAGE_ASYNC_START:
985 case GST_MESSAGE_ASYNC_DONE:
986 case GST_MESSAGE_STATE_CHANGED:
987 /* we only handle messages from pipeline */
988 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
993 case GST_MESSAGE_BUFFERING:
995 gint buffer_percent = 0;
998 gst_message_parse_buffering(message, &buffer_percent);
999 if (buffer_percent != MAX_BUFFER_PERCENT) {
1000 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1004 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1005 LOGW("can't get cmd lock, send msg to bus");
1009 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1010 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1011 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1014 MMPLAYER_CMD_UNLOCK(player);
1027 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1029 MMHandleType attrs = 0;
1030 guint64 data_size = 0;
1032 gint64 pos_nsec = 0;
1035 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1037 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1039 attrs = MMPLAYER_GET_ATTRS(player);
1041 LOGE("fail to get attributes.\n");
1045 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1046 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1048 if (stat(path, &sb) == 0)
1049 data_size = (guint64)sb.st_size;
1050 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1051 data_size = player->http_content_size;
1054 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1055 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1061 __mmplayer_handle_buffering_playback(mm_player_t* player)
1063 int ret = MM_ERROR_NONE;
1064 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1065 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1066 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1067 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1069 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1070 LOGW("do nothing for buffering msg\n");
1071 ret = MM_ERROR_PLAYER_INVALID_STATE;
1075 prev_state = MMPLAYER_PREV_STATE(player);
1076 current_state = MMPLAYER_CURRENT_STATE(player);
1077 target_state = MMPLAYER_TARGET_STATE(player);
1078 pending_state = MMPLAYER_PENDING_STATE(player);
1080 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1081 MMPLAYER_STATE_GET_NAME(prev_state),
1082 MMPLAYER_STATE_GET_NAME(current_state),
1083 MMPLAYER_STATE_GET_NAME(pending_state),
1084 MMPLAYER_STATE_GET_NAME(target_state),
1085 player->streamer->buffering_state);
1087 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1088 /* NOTE : if buffering has done, player has to go to target state. */
1089 switch (target_state) {
1090 case MM_PLAYER_STATE_PAUSED:
1092 switch (pending_state) {
1093 case MM_PLAYER_STATE_PLAYING:
1094 __mmplayer_gst_pause(player, TRUE);
1097 case MM_PLAYER_STATE_PAUSED:
1098 LOGD("player is already going to paused state, there is nothing to do.\n");
1101 case MM_PLAYER_STATE_NONE:
1102 case MM_PLAYER_STATE_NULL:
1103 case MM_PLAYER_STATE_READY:
1105 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1111 case MM_PLAYER_STATE_PLAYING:
1113 switch (pending_state) {
1114 case MM_PLAYER_STATE_NONE:
1116 if (current_state != MM_PLAYER_STATE_PLAYING)
1117 __mmplayer_gst_resume(player, TRUE);
1121 case MM_PLAYER_STATE_PAUSED:
1122 /* NOTE: It should be worked as asynchronously.
1123 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1125 if (current_state == MM_PLAYER_STATE_PLAYING) {
1126 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1127 * The current state should be changed to paused purposely to prevent state conflict.
1129 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1131 __mmplayer_gst_resume(player, TRUE);
1134 case MM_PLAYER_STATE_PLAYING:
1135 LOGD("player is already going to playing state, there is nothing to do.\n");
1138 case MM_PLAYER_STATE_NULL:
1139 case MM_PLAYER_STATE_READY:
1141 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1147 case MM_PLAYER_STATE_NULL:
1148 case MM_PLAYER_STATE_READY:
1149 case MM_PLAYER_STATE_NONE:
1151 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1155 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1156 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1158 switch (pending_state) {
1159 case MM_PLAYER_STATE_NONE:
1161 if (current_state != MM_PLAYER_STATE_PAUSED) {
1162 /* rtsp streaming pause makes rtsp server stop sending data. */
1163 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1164 LOGD("set pause state during buffering\n");
1165 __mmplayer_gst_pause(player, TRUE);
1171 case MM_PLAYER_STATE_PLAYING:
1172 /* rtsp streaming pause makes rtsp server stop sending data. */
1173 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1174 __mmplayer_gst_pause(player, TRUE);
1177 case MM_PLAYER_STATE_PAUSED:
1180 case MM_PLAYER_STATE_NULL:
1181 case MM_PLAYER_STATE_READY:
1183 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1192 static VariantData *
1193 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1195 VariantData *var_info = NULL;
1196 g_return_val_if_fail(self != NULL, NULL);
1198 var_info = g_new0(VariantData, 1);
1199 if (!var_info) return NULL;
1200 var_info->bandwidth = self->bandwidth;
1201 var_info->width = self->width;
1202 var_info->height = self->height;
1207 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1213 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1214 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1216 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1217 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1218 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1220 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1221 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1222 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1225 /* handling audio clip which has vbr. means duration is keep changing */
1226 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1235 __mmplayer_eos_timer_cb(gpointer u_data)
1237 mm_player_t* player = NULL;
1238 MMHandleType attrs = 0;
1241 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1243 player = (mm_player_t*) u_data;
1244 attrs = MMPLAYER_GET_ATTRS(player);
1246 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1250 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1251 if (ret_value != MM_ERROR_NONE)
1252 LOGE("seeking to 0 failed in repeat play");
1255 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1258 /* we are returning FALSE as we need only one posting */
1263 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1265 MMPLAYER_RETURN_IF_FAIL(player);
1267 /* post now if delay is zero */
1268 if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1269 LOGD("eos delay is zero. posting EOS now\n");
1270 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1272 if (player->audio_stream_render_cb)
1273 __mmplayer_cancel_eos_timer(player);
1278 /* cancel if existing */
1279 __mmplayer_cancel_eos_timer(player);
1281 /* init new timeout */
1282 /* NOTE : consider give high priority to this timer */
1283 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1285 player->eos_timer = g_timeout_add(delay_in_ms,
1286 __mmplayer_eos_timer_cb, player);
1288 player->context.global_default = g_main_context_default();
1289 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1291 /* check timer is valid. if not, send EOS now */
1292 if (player->eos_timer == 0) {
1293 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1294 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1298 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1300 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1301 int ret = MM_ERROR_NONE;
1305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1307 if (!player->pending_seek.is_pending) {
1308 LOGD("pending seek is not reserved. nothing to do.\n");
1312 /* check player state if player could pending seek or not. */
1313 current_state = MMPLAYER_CURRENT_STATE(player);
1315 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1316 LOGW("try to pending seek in %s state, try next time. \n",
1317 MMPLAYER_STATE_GET_NAME(current_state));
1321 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1323 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1325 if (MM_ERROR_NONE != ret)
1326 LOGE("failed to seek pending postion. just keep staying current position.\n");
1328 player->pending_seek.is_pending = FALSE;
1336 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1338 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1340 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1342 audiobin = player->pipeline->audiobin; /* can be null */
1343 videobin = player->pipeline->videobin; /* can be null */
1344 textbin = player->pipeline->textbin; /* can be null */
1346 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1348 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1349 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1351 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1352 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1354 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1355 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1361 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1363 MMPlayerGstElement *textbin;
1366 MMPLAYER_RETURN_IF_FAIL(player &&
1368 player->pipeline->textbin);
1370 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1372 textbin = player->pipeline->textbin;
1375 LOGD("Drop subtitle text after getting EOS\n");
1377 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1378 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1380 player->is_subtitle_force_drop = TRUE;
1382 if (player->is_subtitle_force_drop == TRUE) {
1383 LOGD("Enable subtitle data path without drop\n");
1385 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1386 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1388 LOGD("non-connected with external display");
1390 player->is_subtitle_force_drop = FALSE;
1396 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1398 MMHandleType attrs = 0;
1403 /* NOTE : EOS event is comming multiple time. watch out it */
1404 /* check state. we only process EOS when pipeline state goes to PLAYING */
1405 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1406 LOGD("EOS received on non-playing state. ignoring it");
1410 if (player->pipeline && player->pipeline->textbin)
1411 __mmplayer_drop_subtitle(player, TRUE);
1413 if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1414 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1416 /* rewind if repeat count is greater then zero */
1417 /* get play count */
1418 attrs = MMPLAYER_GET_ATTRS(player);
1421 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1423 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1425 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1426 if (player->playback_rate < 0.0) {
1427 player->resumed_by_rewind = TRUE;
1428 _mmplayer_set_mute((MMHandleType)player, 0);
1429 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1432 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1435 player->sent_bos = FALSE;
1437 LOGD("do not post eos msg for repeating");
1442 if (player->pipeline)
1443 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1445 /* post eos message to application */
1446 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1448 /* reset last position */
1449 player->last_position = 0;
1456 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1458 GError *error = NULL;
1459 gchar* debug = NULL;
1463 /* generating debug info before returning error */
1464 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1466 /* get error code */
1467 gst_message_parse_error(msg, &error, &debug);
1469 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1470 /* Note : the streaming error from the streaming source is handled
1471 * using __mmplayer_handle_streaming_error.
1473 __mmplayer_handle_streaming_error(player, msg);
1475 /* dump state of all element */
1476 __mmplayer_dump_pipeline_state(player);
1478 /* traslate gst error code to msl error code. then post it
1479 * to application if needed
1481 __mmplayer_handle_gst_error(player, msg, error);
1484 LOGE("error debug : %s", debug);
1487 MMPLAYER_FREEIF(debug);
1488 g_error_free(error);
1495 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1497 MMMessageParamType msg_param = {0, };
1498 int bRet = MM_ERROR_NONE;
1501 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1503 if (!MMPLAYER_IS_STREAMING(player)) {
1504 LOGW("this is not streaming playback.");
1508 MMPLAYER_CMD_LOCK(player);
1510 if (!player->streamer) {
1511 LOGW("Pipeline is shutting down");
1512 MMPLAYER_CMD_UNLOCK(player);
1516 /* ignore the remained buffering message till getting 100% msg */
1517 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1518 gint buffer_percent = 0;
1520 gst_message_parse_buffering(msg, &buffer_percent);
1522 if (buffer_percent == MAX_BUFFER_PERCENT) {
1523 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1524 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1526 MMPLAYER_CMD_UNLOCK(player);
1530 /* ignore the remained buffering message */
1531 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1532 gint buffer_percent = 0;
1534 gst_message_parse_buffering(msg, &buffer_percent);
1536 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1537 player->streamer->buffering_percent, buffer_percent);
1539 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1540 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1541 player->streamer->buffering_req.is_pre_buffering = FALSE;
1543 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1545 LOGD("interrupted buffering - ignored the remained buffering msg!");
1546 MMPLAYER_CMD_UNLOCK(player);
1551 __mmplayer_update_buffer_setting(player, msg);
1553 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1555 if (bRet == MM_ERROR_NONE) {
1556 msg_param.connection.buffering = player->streamer->buffering_percent;
1557 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1559 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1560 player->pending_resume &&
1561 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1563 player->is_external_subtitle_added_now = FALSE;
1564 player->pending_resume = FALSE;
1565 _mmplayer_resume((MMHandleType)player);
1568 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1569 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1571 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1572 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1573 player->seek_state = MMPLAYER_SEEK_NONE;
1574 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1575 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1576 /* Considering the async state trasition in case of RTSP.
1577 After getting state change gst msg, seek cmpleted msg will be posted. */
1578 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1582 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1583 if (!player->streamer) {
1584 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1585 MMPLAYER_CMD_UNLOCK(player);
1589 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1591 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1592 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1594 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1595 msg_param.connection.buffering = player->streamer->buffering_percent;
1596 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1598 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1601 msg_param.connection.buffering = player->streamer->buffering_percent;
1602 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1605 MMPLAYER_CMD_UNLOCK(player);
1613 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1615 MMPlayerGstElement *mainbin;
1616 const GValue *voldstate, *vnewstate, *vpending;
1617 GstState oldstate = GST_STATE_NULL;
1618 GstState newstate = GST_STATE_NULL;
1619 GstState pending = GST_STATE_NULL;
1622 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1624 mainbin = player->pipeline->mainbin;
1626 /* we only handle messages from pipeline */
1627 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1630 /* get state info from msg */
1631 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1632 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1633 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1635 if (!voldstate || !vnewstate) {
1636 LOGE("received msg has wrong format.");
1640 oldstate = (GstState)voldstate->data[0].v_int;
1641 newstate = (GstState)vnewstate->data[0].v_int;
1643 pending = (GstState)vpending->data[0].v_int;
1645 LOGD("state changed [%s] : %s ---> %s final : %s",
1646 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1647 gst_element_state_get_name((GstState)oldstate),
1648 gst_element_state_get_name((GstState)newstate),
1649 gst_element_state_get_name((GstState)pending));
1651 if (newstate == GST_STATE_PLAYING) {
1652 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1654 int retVal = MM_ERROR_NONE;
1655 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1657 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1659 if (MM_ERROR_NONE != retVal)
1660 LOGE("failed to seek pending postion. just keep staying current position.");
1662 player->pending_seek.is_pending = FALSE;
1666 if (oldstate == newstate) {
1667 LOGD("pipeline reports state transition to old state");
1672 case GST_STATE_PAUSED:
1674 gboolean prepare_async = FALSE;
1676 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1677 // managed prepare async case
1678 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1679 LOGD("checking prepare mode for async transition - %d", prepare_async);
1682 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1683 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1685 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1686 __mm_player_streaming_set_content_bitrate(player->streamer,
1687 player->total_maximum_bitrate, player->total_bitrate);
1689 if (player->pending_seek.is_pending) {
1690 LOGW("trying to do pending seek");
1691 MMPLAYER_CMD_LOCK(player);
1692 __mmplayer_gst_pending_seek(player);
1693 MMPLAYER_CMD_UNLOCK(player);
1699 case GST_STATE_PLAYING:
1701 if (MMPLAYER_IS_STREAMING(player)) {
1702 // managed prepare async case when buffering is completed
1703 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1704 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1705 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1706 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1708 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1710 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1711 if (player->streamer->buffering_percent < 100) {
1713 MMMessageParamType msg_param = {0, };
1714 LOGW("Posting Buffering Completed Message to Application !!!");
1716 msg_param.connection.buffering = 100;
1717 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1722 if (player->gapless.stream_changed) {
1723 __mmplayer_update_content_attrs(player, ATTR_ALL);
1724 player->gapless.stream_changed = FALSE;
1727 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1728 player->seek_state = MMPLAYER_SEEK_NONE;
1729 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1733 case GST_STATE_VOID_PENDING:
1734 case GST_STATE_NULL:
1735 case GST_STATE_READY:
1745 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1747 const gchar *structure_name;
1748 gint count = 0, idx = 0;
1749 MMHandleType attrs = 0;
1752 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1754 attrs = MMPLAYER_GET_ATTRS(player);
1756 LOGE("Failed to get content attribute");
1760 if (gst_message_get_structure(msg) == NULL)
1763 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1764 if (!structure_name)
1767 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1769 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1770 const GValue *var_info = NULL;
1772 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1773 if (var_info != NULL) {
1774 if (player->adaptive_info.var_list)
1775 g_list_free_full(player->adaptive_info.var_list, g_free);
1777 /* share addr or copy the list */
1778 player->adaptive_info.var_list =
1779 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1781 count = g_list_length(player->adaptive_info.var_list);
1783 VariantData *temp = NULL;
1785 /* print out for debug */
1786 LOGD("num of variant_info %d", count);
1787 for (idx = 0; idx < count; idx++) {
1788 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1790 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1796 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1797 gint num_buffers = 0;
1798 gint extra_num_buffers = 0;
1800 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1801 player->video_num_buffers = num_buffers;
1802 LOGD("video_num_buffers : %d", player->video_num_buffers);
1805 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1806 player->video_extra_num_buffers = extra_num_buffers;
1807 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1812 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1813 __mmplayer_track_update_text_attr_info(player, msg);
1815 /* custom message */
1816 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1817 MMMessageParamType msg_param = {0,};
1818 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1819 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1822 /* custom message for RTSP attribute :
1823 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1824 sdp which has contents info is received when rtsp connection is opened.
1825 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1826 if (!strcmp(structure_name, "rtspsrc_properties")) {
1828 gchar *audio_codec = NULL;
1829 gchar *video_codec = NULL;
1830 gchar *video_frame_size = NULL;
1832 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1833 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1834 player->streaming_type = __mmplayer_get_stream_service_type(player);
1836 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1837 LOGD("rtsp_audio_codec : %s", audio_codec);
1839 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1841 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1842 LOGD("rtsp_video_codec : %s", video_codec);
1844 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1846 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1847 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1848 if (video_frame_size) {
1850 char *seperator = strchr(video_frame_size, '-');
1853 char video_width[10] = {0,};
1854 int frame_size_len = strlen(video_frame_size);
1855 int separtor_len = strlen(seperator);
1857 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1858 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1861 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1865 if (mm_attrs_commit_all(attrs))
1866 LOGE("failed to commit.");
1874 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1876 MMPlayerGstElement *mainbin;
1879 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1881 mainbin = player->pipeline->mainbin;
1883 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1885 /* we only handle messages from pipeline */
1886 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1889 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1890 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1891 player->seek_state = MMPLAYER_SEEK_NONE;
1892 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1893 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1894 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1895 LOGD("sync %s state(%s) with parent state(%s)",
1896 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1897 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1898 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1900 /* In case of streaming, pause is required before finishing seeking by buffering.
1901 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1902 Because the buffering state is controlled according to the state transition for force resume,
1903 the decodebin state should be paused as player state. */
1904 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1907 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1908 (player->streamer) &&
1909 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1910 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1911 GstQuery *query = NULL;
1912 gboolean busy = FALSE;
1915 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1916 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1917 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1918 gst_query_parse_buffering_percent(query, &busy, &percent);
1919 gst_query_unref(query);
1921 LOGD("buffered percent(%s): %d\n",
1922 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1926 __mmplayer_handle_buffering_playback(player);
1929 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1938 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1940 mm_player_t* player = (mm_player_t*)(data);
1942 MMPLAYER_RETURN_IF_FAIL(player);
1943 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1945 switch (GST_MESSAGE_TYPE(msg)) {
1946 case GST_MESSAGE_UNKNOWN:
1947 LOGD("unknown message received\n");
1950 case GST_MESSAGE_EOS:
1951 LOGD("GST_MESSAGE_EOS received");
1952 __mmplayer_gst_handle_eos_message(player, msg);
1955 case GST_MESSAGE_ERROR:
1956 __mmplayer_gst_handle_error_message(player, msg);
1959 case GST_MESSAGE_WARNING:
1962 GError* error = NULL;
1964 gst_message_parse_warning(msg, &error, &debug);
1966 LOGD("warning : %s\n", error->message);
1967 LOGD("debug : %s\n", debug);
1969 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1971 MMPLAYER_FREEIF(debug);
1972 g_error_free(error);
1976 case GST_MESSAGE_TAG:
1978 LOGD("GST_MESSAGE_TAG\n");
1979 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1980 LOGW("failed to extract tags from gstmessage\n");
1984 case GST_MESSAGE_BUFFERING:
1985 __mmplayer_gst_handle_buffering_message(player, msg);
1988 case GST_MESSAGE_STATE_CHANGED:
1989 __mmplayer_gst_handle_state_message(player, msg);
1992 case GST_MESSAGE_CLOCK_LOST:
1994 GstClock *clock = NULL;
1995 gboolean need_new_clock = FALSE;
1997 gst_message_parse_clock_lost(msg, &clock);
1998 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2000 if (!player->videodec_linked)
2001 need_new_clock = TRUE;
2002 else if (!player->ini.use_system_clock)
2003 need_new_clock = TRUE;
2005 if (need_new_clock) {
2006 LOGD("Provide clock is TRUE, do pause->resume\n");
2007 __mmplayer_gst_pause(player, FALSE);
2008 __mmplayer_gst_resume(player, FALSE);
2013 case GST_MESSAGE_NEW_CLOCK:
2015 GstClock *clock = NULL;
2016 gst_message_parse_new_clock(msg, &clock);
2017 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2021 case GST_MESSAGE_ELEMENT:
2022 __mmplayer_gst_handle_element_message(player, msg);
2025 case GST_MESSAGE_DURATION_CHANGED:
2027 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2028 if (!__mmplayer_gst_handle_duration(player, msg))
2029 LOGW("failed to update duration");
2033 case GST_MESSAGE_ASYNC_START:
2034 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2037 case GST_MESSAGE_ASYNC_DONE:
2038 __mmplayer_gst_handle_async_done_message(player, msg);
2041 #if 0 /* delete unnecessary logs */
2042 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2043 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2044 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2045 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2046 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2047 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2048 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2049 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2050 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2051 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2052 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2053 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2054 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2055 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2056 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2063 /* should not call 'gst_message_unref(msg)' */
2067 static GstBusSyncReply
2068 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2070 mm_player_t *player = (mm_player_t *)data;
2071 GstBusSyncReply reply = GST_BUS_DROP;
2073 if (!(player->pipeline && player->pipeline->mainbin)) {
2074 LOGE("player pipeline handle is null");
2075 return GST_BUS_PASS;
2078 if (!__mmplayer_gst_check_useful_message(player, message)) {
2079 gst_message_unref(message);
2080 return GST_BUS_DROP;
2083 switch (GST_MESSAGE_TYPE(message)) {
2084 case GST_MESSAGE_TAG:
2085 __mmplayer_gst_extract_tag_from_msg(player, message);
2089 GstTagList *tags = NULL;
2091 gst_message_parse_tag(message, &tags);
2093 LOGE("TAGS received from element \"%s\".\n",
2094 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2096 gst_tag_list_foreach(tags, print_tag, NULL);
2097 gst_tag_list_unref(tags);
2105 case GST_MESSAGE_DURATION_CHANGED:
2106 __mmplayer_gst_handle_duration(player, message);
2108 case GST_MESSAGE_ASYNC_DONE:
2109 /* NOTE:Don't call gst_callback directly
2110 * because previous frame can be showed even though this message is received for seek.
2113 reply = GST_BUS_PASS;
2117 if (reply == GST_BUS_DROP)
2118 gst_message_unref(message);
2124 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2126 GstElement *appsrc = element;
2127 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2128 GstBuffer *buffer = NULL;
2129 GstFlowReturn ret = GST_FLOW_OK;
2132 MMPLAYER_RETURN_IF_FAIL(element);
2133 MMPLAYER_RETURN_IF_FAIL(buf);
2135 buffer = gst_buffer_new();
2137 if (buf->offset < 0 || buf->len < 0) {
2138 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2142 if (buf->offset >= buf->len) {
2143 LOGD("call eos appsrc");
2144 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2148 if (buf->len - buf->offset < size)
2149 len = buf->len - buf->offset;
2151 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2152 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2153 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2155 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2156 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2162 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2164 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2166 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2168 buf->offset = (int)size;
2174 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2176 mm_player_t *player = (mm_player_t*)user_data;
2177 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2178 guint64 current_level_bytes = 0;
2180 MMPLAYER_RETURN_IF_FAIL(player);
2182 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2183 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2184 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2185 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2186 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2187 type = MM_PLAYER_STREAM_TYPE_TEXT;
2189 LOGE("can not enter here");
2193 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2195 LOGI("type: %d, level: %"G_GUINT64_FORMAT, type, current_level_bytes);
2197 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2198 if (player->media_stream_buffer_status_cb[type])
2199 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2200 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2204 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2206 mm_player_t *player = (mm_player_t*)user_data;
2207 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2208 guint64 current_level_bytes = 0;
2210 MMPLAYER_RETURN_IF_FAIL(player);
2212 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2213 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2214 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2215 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2216 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2217 type = MM_PLAYER_STREAM_TYPE_TEXT;
2219 LOGE("can not enter here");
2223 LOGI("type: %d, buffer is full", type);
2225 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2227 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2229 if (player->media_stream_buffer_status_cb[type])
2230 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2232 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2236 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2238 mm_player_t *player = (mm_player_t*)user_data;
2239 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2241 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2243 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2244 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2245 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2246 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2247 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2248 type = MM_PLAYER_STREAM_TYPE_TEXT;
2250 LOGE("can not enter here");
2254 LOGD("type: %d, pos: %"G_GUINT64_FORMAT, type, position);
2255 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2257 if (player->media_stream_seek_data_cb[type])
2258 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2259 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2265 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2267 #define MAX_LEN_NAME 20
2269 gboolean ret = FALSE;
2270 GstPad *sinkpad = NULL;
2271 gchar *prefix = NULL;
2272 gchar dec_name[MAX_LEN_NAME] = {0};
2273 enum MainElementID elem_id = MMPLAYER_M_NUM;
2275 MMPlayerGstElement *mainbin = NULL;
2276 GstElement *decodebin = NULL;
2277 GstCaps *dec_caps = NULL;
2281 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2283 player->pipeline->mainbin, FALSE);
2284 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2286 mainbin = player->pipeline->mainbin;
2288 case MM_PLAYER_STREAM_TYPE_AUDIO:
2290 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2292 case MM_PLAYER_STREAM_TYPE_VIDEO:
2294 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2297 LOGE("invalid type %d", type);
2301 if (mainbin[elem_id].gst) {
2302 LOGE("elem(%d) is already created", elem_id);
2306 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2308 /* create decodebin */
2309 decodebin = gst_element_factory_make("decodebin", dec_name);
2311 LOGE("failed to create %s", dec_name);
2315 mainbin[elem_id].id = elem_id;
2316 mainbin[elem_id].gst = decodebin;
2318 /* raw pad handling signal */
2319 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2320 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2322 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2323 before looking for any elements that can handle that stream.*/
2324 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2325 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2327 /* This signal is emitted when a element is added to the bin.*/
2328 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2329 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2331 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2332 LOGE("failed to add new decodebin");
2336 dec_caps = gst_pad_query_caps(srcpad, NULL);
2338 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2339 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2340 gst_caps_unref(dec_caps);
2343 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2345 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2346 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2349 gst_object_unref(GST_OBJECT(sinkpad));
2351 gst_element_sync_state_with_parent(decodebin);
2357 gst_object_unref(GST_OBJECT(sinkpad));
2359 if (mainbin[elem_id].gst) {
2360 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2361 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2362 gst_object_unref(mainbin[elem_id].gst);
2363 mainbin[elem_id].gst = NULL;
2371 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2373 #define MAX_LEN_NAME 20
2374 MMPlayerGstElement *mainbin = NULL;
2375 gchar *prefix = NULL;
2376 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2378 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2379 GstElement *src = NULL, *queue = NULL;
2380 GstPad *srcpad = NULL;
2383 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2384 player->pipeline->mainbin, FALSE);
2386 mainbin = player->pipeline->mainbin;
2388 LOGD("type(%d) path is creating", type);
2390 case MM_PLAYER_STREAM_TYPE_AUDIO:
2392 if (mainbin[MMPLAYER_M_SRC].gst)
2393 src_id = MMPLAYER_M_2ND_SRC;
2395 src_id = MMPLAYER_M_SRC;
2396 queue_id = MMPLAYER_M_A_BUFFER;
2398 case MM_PLAYER_STREAM_TYPE_VIDEO:
2400 src_id = MMPLAYER_M_SRC;
2401 queue_id = MMPLAYER_M_V_BUFFER;
2403 case MM_PLAYER_STREAM_TYPE_TEXT:
2404 prefix = "subtitle";
2405 src_id = MMPLAYER_M_SUBSRC;
2406 queue_id = MMPLAYER_M_S_BUFFER;
2409 LOGE("invalid type %d", type);
2413 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2414 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2417 src = gst_element_factory_make("appsrc", src_name);
2419 LOGF("failed to create %s", src_name);
2423 mainbin[src_id].id = src_id;
2424 mainbin[src_id].gst = src;
2426 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2427 "caps", caps, NULL);
2429 /* size of many video frames are larger than default blocksize as 4096 */
2430 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2431 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2433 if (player->media_stream_buffer_max_size[type] > 0)
2434 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2436 if (player->media_stream_buffer_min_percent[type] > 0)
2437 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2439 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2440 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2442 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2443 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2444 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2445 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2446 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2447 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2450 queue = gst_element_factory_make("queue2", queue_name);
2452 LOGE("failed to create %s", queue_name);
2455 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2457 mainbin[queue_id].id = queue_id;
2458 mainbin[queue_id].gst = queue;
2460 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2461 LOGE("failed to add src");
2465 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2466 LOGE("failed to add queue");
2470 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2471 LOGE("failed to link src and queue");
2475 /* create decoder */
2476 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2478 LOGE("failed to get srcpad of queue");
2482 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2483 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2485 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2486 LOGE("failed to create decoder");
2487 gst_object_unref(GST_OBJECT(srcpad));
2491 gst_object_unref(GST_OBJECT(srcpad));
2495 if (mainbin[src_id].gst) {
2496 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2497 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2498 gst_object_unref(mainbin[src_id].gst);
2499 mainbin[src_id].gst = NULL;
2502 if (mainbin[queue_id].gst) {
2503 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2504 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2505 gst_object_unref(mainbin[queue_id].gst);
2506 mainbin[queue_id].gst = NULL;
2513 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2515 GstPad *sinkpad = NULL;
2516 GstCaps *caps = NULL;
2517 GstElement *new_element = NULL;
2518 GstStructure *str = NULL;
2519 const gchar *name = NULL;
2521 mm_player_t *player = (mm_player_t*) data;
2525 MMPLAYER_RETURN_IF_FAIL(element && pad);
2526 MMPLAYER_RETURN_IF_FAIL(player &&
2528 player->pipeline->mainbin);
2530 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2531 * num_dynamic_pad will decreased after creating a sinkbin.
2533 player->num_dynamic_pad++;
2534 LOGD("stream count inc : %d", player->num_dynamic_pad);
2536 caps = gst_pad_query_caps(pad, NULL);
2537 MMPLAYER_CHECK_NULL(caps);
2539 str = gst_caps_get_structure (caps, 0);
2540 name = gst_structure_get_string(str, "media");
2542 LOGE("cannot get mimetype from structure.\n");
2546 if (strstr(name, "video")) {
2548 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2550 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2551 if (player->v_stream_caps) {
2552 gst_caps_unref(player->v_stream_caps);
2553 player->v_stream_caps = NULL;
2556 new_element = gst_element_factory_make("fakesink", NULL);
2557 player->num_dynamic_pad--;
2562 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2563 LOGE("failed to autoplug for caps");
2567 gst_caps_unref(caps);
2572 /* excute new_element if created*/
2574 LOGD("adding new element to pipeline\n");
2576 /* set state to READY before add to bin */
2577 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2579 /* add new element to the pipeline */
2580 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2581 LOGE("failed to add autoplug element to bin\n");
2585 /* get pad from element */
2586 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2588 LOGE("failed to get sinkpad from autoplug element\n");
2593 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2594 LOGE("failed to link autoplug element\n");
2598 gst_object_unref(sinkpad);
2601 /* run. setting PLAYING here since streamming source is live source */
2602 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2606 gst_caps_unref(caps);
2612 STATE_CHANGE_FAILED:
2614 /* FIXIT : take care if new_element has already added to pipeline */
2616 gst_object_unref(GST_OBJECT(new_element));
2619 gst_object_unref(GST_OBJECT(sinkpad));
2622 gst_caps_unref(caps);
2624 /* FIXIT : how to inform this error to MSL ????? */
2625 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2626 * then post an error to application
2631 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2633 mm_player_t* player = (mm_player_t*) data;
2637 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2638 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2639 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2640 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2642 * [1] audio and video will be dumped with filesink.
2643 * [2] autoplugging is done by just using pad caps.
2644 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2645 * and the video will be dumped via filesink.
2647 if (player->num_dynamic_pad == 0) {
2648 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2650 if (!__mmplayer_gst_remove_fakesink(player,
2651 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2652 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2653 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2654 * source element are not same. To overcome this situation, this function will called
2655 * several places and several times. Therefore, this is not an error case.
2660 /* create dot before error-return. for debugging */
2661 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2663 player->no_more_pad = TRUE;
2669 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2671 GstElement* element = NULL;
2672 gchar *user_agent = NULL;
2673 MMHandleType attrs = 0;
2676 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2678 /* get profile attribute */
2679 attrs = MMPLAYER_GET_ATTRS(player);
2681 LOGE("failed to get content attribute");
2685 element = gst_element_factory_make("rtspsrc", "rtsp source");
2687 LOGE("failed to create rtspsrc element");
2692 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2694 SECURE_LOGD("user_agent : %s", user_agent);
2696 /* setting property to streaming source */
2697 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2699 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2701 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2702 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2703 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2704 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2711 __mmplayer_gst_make_http_src(mm_player_t* player)
2713 GstElement* element = NULL;
2714 MMHandleType attrs = 0;
2715 gchar *user_agent, *cookies, **cookie_list;
2716 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2717 user_agent = cookies = NULL;
2721 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2723 /* get profile attribute */
2724 attrs = MMPLAYER_GET_ATTRS(player);
2726 LOGE("failed to get content attribute");
2730 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2732 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2734 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2739 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2740 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2742 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2743 http_timeout = player->ini.http_timeout;
2746 SECURE_LOGD("location : %s", player->profile.uri);
2747 SECURE_LOGD("cookies : %s", cookies);
2748 SECURE_LOGD("user_agent : %s", user_agent);
2749 LOGD("timeout : %d", http_timeout);
2751 /* setting property to streaming source */
2752 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2753 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2755 /* parsing cookies */
2756 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2757 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2758 g_strfreev(cookie_list);
2762 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2764 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2765 LOGW("[DASH] this is still experimental feature");
2772 __mmplayer_gst_make_file_src(mm_player_t* player)
2774 GstElement* element = NULL;
2777 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2779 LOGD("using filesrc for 'file://' handler");
2780 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2781 LOGE("failed to get storage info");
2785 element = gst_element_factory_make("filesrc", "source");
2787 LOGE("failed to create filesrc");
2791 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2797 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2799 mm_player_t *player = (mm_player_t *) data;
2801 g_return_val_if_fail(player, FALSE);
2802 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2804 gst_message_ref(msg);
2806 g_mutex_lock(&player->bus_msg_q_lock);
2807 g_queue_push_tail(player->bus_msg_q, msg);
2808 g_mutex_unlock(&player->bus_msg_q_lock);
2810 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2811 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2812 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2816 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2818 mm_player_t *player = (mm_player_t*)(data);
2819 GstMessage *msg = NULL;
2823 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2825 player->pipeline->mainbin &&
2826 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2829 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2831 LOGE("cannot get BUS from the pipeline");
2835 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2837 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2838 while (!player->bus_msg_thread_exit) {
2839 g_mutex_lock(&player->bus_msg_q_lock);
2840 msg = g_queue_pop_head(player->bus_msg_q);
2841 g_mutex_unlock(&player->bus_msg_q_lock);
2843 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2846 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2847 /* handle the gst msg */
2848 __mmplayer_gst_bus_msg_callback(msg, player);
2849 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2850 gst_message_unref(msg);
2853 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2854 gst_object_unref(GST_OBJECT(bus));
2861 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2863 gint64 dur_nsec = 0;
2866 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2868 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2869 return MM_ERROR_NONE;
2871 /* NOTE : duration cannot be zero except live streaming.
2872 * Since some element could have some timing problemn with quering duration, try again.
2874 if (player->duration == 0) {
2875 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2876 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2877 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2878 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2879 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2880 player->pending_seek.is_pending = TRUE;
2881 player->pending_seek.pos = position;
2882 player->seek_state = MMPLAYER_SEEK_NONE;
2883 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2884 return MM_ERROR_PLAYER_NO_OP;
2886 player->seek_state = MMPLAYER_SEEK_NONE;
2887 return MM_ERROR_PLAYER_SEEK;
2890 player->duration = dur_nsec;
2893 if (player->duration > 0 && player->duration < position) {
2894 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2895 return MM_ERROR_INVALID_ARGUMENT;
2899 return MM_ERROR_NONE;
2903 __mmplayer_gst_check_seekable(mm_player_t* player)
2905 GstQuery *query = NULL;
2906 gboolean seekable = FALSE;
2908 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2912 query = gst_query_new_seeking(GST_FORMAT_TIME);
2913 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2914 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2915 gst_query_unref(query);
2918 LOGW("non-seekable content");
2919 player->seek_state = MMPLAYER_SEEK_NONE;
2923 LOGW("failed to get seeking query");
2924 gst_query_unref(query); /* keep seeking operation */
2935 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2937 GstState element_state = GST_STATE_VOID_PENDING;
2938 GstState element_pending_state = GST_STATE_VOID_PENDING;
2939 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2944 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2946 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2949 ret = gst_element_set_state(element, state);
2951 if (ret == GST_STATE_CHANGE_FAILURE) {
2952 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2954 /* dump state of all element */
2955 __mmplayer_dump_pipeline_state(player);
2957 return MM_ERROR_PLAYER_INTERNAL;
2960 /* return here so state transition to be done in async mode */
2962 LOGD("async state transition. not waiting for state complete.\n");
2963 return MM_ERROR_NONE;
2966 /* wait for state transition */
2967 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2969 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2970 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
2971 GST_ELEMENT_NAME(element),
2972 gst_element_state_get_name(state), timeout);
2974 LOGE(" [%s] state : %s pending : %s \n",
2975 GST_ELEMENT_NAME(element),
2976 gst_element_state_get_name(element_state),
2977 gst_element_state_get_name(element_pending_state));
2979 /* dump state of all element */
2980 __mmplayer_dump_pipeline_state(player);
2982 return MM_ERROR_PLAYER_INTERNAL;
2985 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
2989 return MM_ERROR_NONE;
2992 int __mmplayer_gst_start(mm_player_t* player)
2994 int ret = MM_ERROR_NONE;
2995 gboolean async = FALSE;
2999 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3001 /* NOTE : if SetPosition was called before Start. do it now */
3002 /* streaming doesn't support it. so it should be always sync */
3003 /* !!create one more api to check if there is pending seek rather than checking variables */
3004 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3005 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3006 ret = __mmplayer_gst_pause(player, FALSE);
3007 if (ret != MM_ERROR_NONE) {
3008 LOGE("failed to set state to PAUSED for pending seek");
3012 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3013 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3014 LOGW("failed to seek pending postion. starting from the begin of content");
3017 LOGD("current state before doing transition");
3018 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3019 MMPLAYER_PRINT_STATE(player);
3021 /* set pipeline state to PLAYING */
3022 ret = __mmplayer_gst_set_state(player,
3023 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3025 if (ret == MM_ERROR_NONE) {
3026 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3028 LOGE("failed to set state to PLAYING");
3032 /* generating debug info before returning error */
3033 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3040 int __mmplayer_gst_stop(mm_player_t* player)
3042 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3043 MMHandleType attrs = 0;
3044 gboolean rewind = FALSE;
3046 int ret = MM_ERROR_NONE;
3050 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3051 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3053 LOGD("current state before doing transition");
3054 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3055 MMPLAYER_PRINT_STATE(player);
3057 attrs = MMPLAYER_GET_ATTRS(player);
3059 LOGE("cannot get content attribute\n");
3060 return MM_ERROR_PLAYER_INTERNAL;
3063 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3064 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3066 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3067 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3070 if (player->es_player_push_mode) {
3071 /* disable the async state transition because there could be no data in the pipeline */
3072 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3076 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3078 if (player->es_player_push_mode) {
3079 /* enable the async state transition as default operation */
3080 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3083 /* return if set_state has failed */
3084 if (ret != MM_ERROR_NONE) {
3085 LOGE("failed to set state.\n");
3091 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3092 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3093 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3094 LOGW("failed to rewind\n");
3095 ret = MM_ERROR_PLAYER_SEEK;
3100 player->sent_bos = FALSE;
3102 if (player->es_player_push_mode) //for cloudgame
3105 /* wait for seek to complete */
3106 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3107 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3108 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3110 LOGE("fail to stop player.\n");
3111 ret = MM_ERROR_PLAYER_INTERNAL;
3112 __mmplayer_dump_pipeline_state(player);
3115 /* generate dot file if enabled */
3116 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3123 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3125 int ret = MM_ERROR_NONE;
3129 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3130 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3132 LOGD("current state before doing transition");
3133 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3134 MMPLAYER_PRINT_STATE(player);
3136 /* set pipeline status to PAUSED */
3137 ret = __mmplayer_gst_set_state(player,
3138 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3140 if (FALSE == async) {
3141 if (ret != MM_ERROR_NONE) {
3142 GstMessage *msg = NULL;
3143 GTimer *timer = NULL;
3144 gdouble MAX_TIMEOUT_SEC = 3;
3146 LOGE("failed to set state to PAUSED");
3148 if (!player->bus_watcher) {
3149 LOGE("there is no bus msg thread. pipeline is shutting down.");
3153 if (player->msg_posted) {
3154 LOGE("error msg is already posted.");
3158 timer = g_timer_new();
3159 g_timer_start(timer);
3161 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3164 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3166 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3167 GError *error = NULL;
3169 /* parse error code */
3170 gst_message_parse_error(msg, &error, NULL);
3172 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3173 /* Note : the streaming error from the streaming source is handled
3174 * using __mmplayer_handle_streaming_error.
3176 __mmplayer_handle_streaming_error(player, msg);
3179 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3181 if (error->domain == GST_STREAM_ERROR)
3182 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3183 else if (error->domain == GST_RESOURCE_ERROR)
3184 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3185 else if (error->domain == GST_LIBRARY_ERROR)
3186 ret = __mmplayer_gst_handle_library_error(player, error->code);
3187 else if (error->domain == GST_CORE_ERROR)
3188 ret = __mmplayer_gst_handle_core_error(player, error->code);
3190 g_error_free(error);
3192 player->msg_posted = TRUE;
3194 gst_message_unref(msg);
3196 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3198 gst_object_unref(bus);
3199 g_timer_stop(timer);
3200 g_timer_destroy(timer);
3204 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3205 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3207 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3210 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3214 /* generate dot file before returning error */
3215 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3222 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3224 int ret = MM_ERROR_NONE;
3229 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3230 MM_ERROR_PLAYER_NOT_INITIALIZED);
3232 LOGD("current state before doing transition");
3233 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3234 MMPLAYER_PRINT_STATE(player);
3237 LOGD("do async state transition to PLAYING");
3239 /* set pipeline state to PLAYING */
3240 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3242 ret = __mmplayer_gst_set_state(player,
3243 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3244 if (ret != MM_ERROR_NONE) {
3245 LOGE("failed to set state to PLAYING");
3249 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3253 /* generate dot file */
3254 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3261 /* sending event to one of sinkelements */
3263 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3265 GstEvent * event2 = NULL;
3266 GList *sinks = NULL;
3267 gboolean res = FALSE;
3270 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3271 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3273 /* While adding subtitles in live feeds seek is getting called.
3274 Adding defensive check in framework layer.*/
3275 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3276 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3277 LOGE("Should not send seek event during live playback");
3282 if (player->play_subtitle)
3283 event2 = gst_event_copy((const GstEvent *)event);
3285 sinks = player->sink_elements;
3287 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3289 if (GST_IS_ELEMENT(sink)) {
3290 /* keep ref to the event */
3291 gst_event_ref(event);
3293 if ((res = gst_element_send_event(sink, event))) {
3294 LOGD("sending event[%s] to sink element [%s] success!\n",
3295 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3297 /* rtsp case, asyn_done is not called after seek during pause state */
3298 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3299 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3300 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3301 LOGD("RTSP seek completed, after pause state..\n");
3302 player->seek_state = MMPLAYER_SEEK_NONE;
3303 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3309 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3310 sinks = g_list_next(sinks);
3317 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3318 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3321 sinks = g_list_next(sinks);
3324 /* Note : Textbin is not linked to the video or audio bin.
3325 * It needs to send the event to the text sink seperatelly.
3327 if (player->play_subtitle && player->pipeline) {
3328 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3330 if (GST_IS_ELEMENT(text_sink)) {
3331 /* keep ref to the event */
3332 gst_event_ref(event2);
3334 if ((res = gst_element_send_event(text_sink, event2)))
3335 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3336 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3338 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3339 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3341 gst_event_unref(event2);
3345 gst_event_unref(event);
3353 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3354 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3355 gint64 cur, GstSeekType stop_type, gint64 stop)
3357 GstEvent* event = NULL;
3358 gboolean result = FALSE;
3362 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3364 if (player->pipeline && player->pipeline->textbin)
3365 __mmplayer_drop_subtitle(player, FALSE);
3367 event = gst_event_new_seek(rate, format, flags, cur_type,
3368 cur, stop_type, stop);
3370 result = __mmplayer_gst_send_event_to_sink(player, event);
3378 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3380 int ret = MM_ERROR_NONE;
3381 gint64 pos_nsec = 0;
3382 gboolean accurated = FALSE;
3383 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3386 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3387 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3389 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3390 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3393 ret = __mmplayer_gst_check_duration(player, position);
3394 if (ret != MM_ERROR_NONE) {
3395 LOGE("failed to check duration 0x%X", ret);
3396 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3399 if (!__mmplayer_gst_check_seekable(player))
3400 return MM_ERROR_PLAYER_NO_OP;
3402 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3403 position, player->playback_rate, player->duration);
3405 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3406 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3407 This causes problem is position calculation during normal pause resume scenarios also.
3408 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3409 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3410 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3411 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3412 LOGW("getting current position failed in seek");
3414 player->last_position = pos_nsec;
3415 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3418 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3419 LOGD("not completed seek");
3420 return MM_ERROR_PLAYER_DOING_SEEK;
3423 if (!internal_called)
3424 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3426 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3427 that's why set position through property. */
3428 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3429 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3430 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3431 (!player->videodec_linked) && (!player->audiodec_linked)) {
3433 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3434 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3436 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3437 player->seek_state = MMPLAYER_SEEK_NONE;
3438 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3440 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3442 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3444 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3446 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3447 GST_FORMAT_TIME, seek_flags,
3448 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3449 LOGE("failed to set position");
3454 /* NOTE : store last seeking point to overcome some bad operation
3455 * (returning zero when getting current position) of some elements
3457 player->last_position = position;
3459 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3460 if (player->playback_rate > 1.0)
3461 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3463 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3464 LOGD("buffering should be reset after seeking");
3465 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3466 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3470 return MM_ERROR_NONE;
3473 player->pending_seek.is_pending = TRUE;
3474 player->pending_seek.pos = position;
3476 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3477 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3478 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3479 player->pending_seek.pos);
3481 return MM_ERROR_NONE;
3484 player->seek_state = MMPLAYER_SEEK_NONE;
3485 return MM_ERROR_PLAYER_SEEK;
3489 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3491 #define TRICKPLAY_OFFSET GST_MSECOND
3493 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3494 gint64 pos_nsec = 0;
3495 gboolean ret = TRUE;
3497 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3498 MM_ERROR_PLAYER_NOT_INITIALIZED);
3500 current_state = MMPLAYER_CURRENT_STATE(player);
3502 /* NOTE : query position except paused state to overcome some bad operation
3503 * please refer to below comments in details
3505 if (current_state != MM_PLAYER_STATE_PAUSED)
3506 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3508 /* NOTE : get last point to overcome some bad operation of some elements
3509 *(returning zero when getting current position in paused state
3510 * and when failed to get postion during seeking
3512 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3513 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3515 if (player->playback_rate < 0.0)
3516 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3518 pos_nsec = player->last_position;
3521 pos_nsec = player->last_position;
3523 player->last_position = pos_nsec;
3525 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3528 if (player->duration > 0 && pos_nsec > player->duration)
3529 pos_nsec = player->duration;
3531 player->last_position = pos_nsec;
3534 *position = pos_nsec;
3536 return MM_ERROR_NONE;
3539 int __mmplayer_gst_get_buffer_position(mm_player_t *player, int *start_pos, int *end_pos)
3541 #define STREAMING_IS_FINISHED 0
3542 #define BUFFERING_MAX_PER 100
3543 #define DEFAULT_PER_VALUE -1
3544 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3546 MMPlayerGstElement *mainbin = NULL;
3547 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3548 gint64 buffered_total = 0;
3549 gint64 position = 0;
3550 gint buffered_sec = -1;
3551 GstBufferingMode mode = GST_BUFFERING_STREAM;
3552 gint64 content_size_time = player->duration;
3553 guint64 content_size_bytes = player->http_content_size;
3555 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3557 player->pipeline->mainbin,
3558 MM_ERROR_PLAYER_NOT_INITIALIZED);
3560 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3565 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3566 /* and rtsp is not ready yet. */
3567 LOGW("it's only used for http streaming case");
3568 return MM_ERROR_PLAYER_NO_OP;
3571 if (content_size_time <= 0 || content_size_bytes <= 0) {
3572 LOGW("there is no content size");
3573 return MM_ERROR_NONE;
3576 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3577 LOGW("fail to get current position");
3578 return MM_ERROR_NONE;
3581 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3582 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3584 mainbin = player->pipeline->mainbin;
3585 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3587 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3588 GstQuery *query = NULL;
3589 gint byte_in_rate = 0, byte_out_rate = 0;
3590 gint64 estimated_total = 0;
3592 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3593 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3594 LOGW("fail to get buffering query from queue2");
3596 gst_query_unref(query);
3597 return MM_ERROR_NONE;
3600 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3601 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3603 if (mode == GST_BUFFERING_STREAM) {
3604 /* using only queue in case of push mode(ts / mp3) */
3605 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3606 GST_FORMAT_BYTES, &buffered_total)) {
3607 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3608 end_per = 100 * buffered_total / content_size_bytes;
3611 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3613 guint num_of_ranges = 0;
3614 gint64 start_byte = 0, stop_byte = 0;
3616 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3617 if (estimated_total != STREAMING_IS_FINISHED) {
3618 /* buffered size info from queue2 */
3619 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3620 for (idx = 0; idx < num_of_ranges; idx++) {
3621 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3622 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3624 buffered_total += (stop_byte - start_byte);
3627 end_per = BUFFERING_MAX_PER;
3629 gst_query_unref(query);
3632 if (end_per == DEFAULT_PER_VALUE) {
3633 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3635 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3637 /* buffered size info from multiqueue */
3638 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3639 guint curr_size_bytes = 0;
3640 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3641 "curr-size-bytes", &curr_size_bytes, NULL);
3642 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3643 buffered_total += curr_size_bytes;
3646 if (avg_byterate > 0)
3647 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3648 else if (player->total_maximum_bitrate > 0)
3649 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3650 else if (player->total_bitrate > 0)
3651 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3653 if (buffered_sec >= 0)
3654 end_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3658 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3659 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3661 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3662 buffered_total, buffered_sec, *start_pos, *end_pos);
3664 return MM_ERROR_NONE;
3667 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3669 GstElement* element = NULL;
3672 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3673 player->pipeline->mainbin, NULL);
3675 /* setup source for gapless play */
3676 switch (player->profile.uri_type) {
3678 case MM_PLAYER_URI_TYPE_FILE:
3679 element = __mmplayer_gst_make_file_src(player);
3681 case MM_PLAYER_URI_TYPE_URL_HTTP:
3682 element = __mmplayer_gst_make_http_src(player);
3685 LOGE("not support uri type %d", player->profile.uri_type);
3690 LOGE("failed to create source element");
3698 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3700 MMHandleType attrs = 0;
3703 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3704 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3706 /* get profile attribute */
3707 attrs = MMPLAYER_GET_ATTRS(player);
3709 LOGE("failed to get content attribute");
3710 return MM_ERROR_PLAYER_INTERNAL;
3713 SECURE_LOGD("uri : %s", player->profile.uri);
3715 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3716 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3717 LOGE("failed to commit");
3719 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3720 return MM_ERROR_PLAYER_INTERNAL;
3722 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3723 return MM_ERROR_PLAYER_INTERNAL;
3725 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3726 return MM_ERROR_PLAYER_INTERNAL;
3729 return MM_ERROR_NONE;
3732 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3734 MMPlayerGstElement *mainbin = NULL;
3735 GstElement* src_elem = NULL;
3736 GstElement *autoplug_elem = NULL;
3737 GList* element_bucket = NULL;
3738 MMHandleType attrs = 0;
3739 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3742 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3743 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3745 /* get profile attribute */
3746 attrs = MMPLAYER_GET_ATTRS(player);
3748 LOGE("failed to get content attribute");
3749 return MM_ERROR_PLAYER_INTERNAL;
3752 LOGD("uri type %d", player->profile.uri_type);
3754 /* create source element */
3755 switch (player->profile.uri_type) {
3756 case MM_PLAYER_URI_TYPE_URL_RTSP:
3757 src_elem = __mmplayer_gst_make_rtsp_src(player);
3759 case MM_PLAYER_URI_TYPE_URL_HTTP:
3760 src_elem = __mmplayer_gst_make_http_src(player);
3762 case MM_PLAYER_URI_TYPE_FILE:
3763 src_elem = __mmplayer_gst_make_file_src(player);
3765 case MM_PLAYER_URI_TYPE_SS:
3767 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3768 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3770 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3774 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3775 LOGD("get timeout from ini");
3776 http_timeout = player->ini.http_timeout;
3779 /* setting property to streaming source */
3780 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3783 case MM_PLAYER_URI_TYPE_MEM:
3785 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3787 src_elem = gst_element_factory_make("appsrc", "mem-source");
3789 LOGE("failed to create appsrc element");
3793 g_object_set(src_elem, "stream-type", stream_type,
3794 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3796 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3797 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3798 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3799 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3803 LOGE("not support uri type");
3808 LOGE("failed to create source element");
3809 return MM_ERROR_PLAYER_INTERNAL;
3812 mainbin = player->pipeline->mainbin;
3814 /* take source element */
3815 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3817 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3818 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3819 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3821 /* create next element for auto-plugging */
3822 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3823 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3824 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3825 if (!autoplug_elem) {
3826 LOGE("failed to create typefind element");
3830 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3831 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3832 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3833 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3834 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3835 if (!autoplug_elem) {
3836 LOGE("failed to create decodebin");
3840 /* default size of mq in decodebin is 2M
3841 * but it can cause blocking issue during seeking depends on content. */
3842 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
3845 if (autoplug_elem) {
3846 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3847 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3848 mainbin[autoplug_elem_id].gst = autoplug_elem;
3850 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3853 /* add elements to pipeline */
3854 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3855 LOGE("failed to add elements to pipeline");
3859 /* linking elements in the bucket by added order. */
3860 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3861 LOGE("failed to link some elements");
3865 /* FIXME: need to check whether this is required or not. */
3866 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3867 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3868 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3869 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3871 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3872 LOGE("failed to create fakesink");
3875 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3877 /* take ownership of fakesink. we are reusing it */
3878 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3880 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3881 LOGE("failed to add fakesink to bin");
3882 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3887 g_list_free(element_bucket);
3890 return MM_ERROR_NONE;
3893 g_list_free(element_bucket);
3895 if (mainbin[MMPLAYER_M_SRC].gst)
3896 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3898 if (mainbin[autoplug_elem_id].gst)
3899 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3901 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3902 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3904 mainbin[MMPLAYER_M_SRC].gst = NULL;
3905 mainbin[autoplug_elem_id].gst = NULL;
3906 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3908 return MM_ERROR_PLAYER_INTERNAL;
3911 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
3914 MMPlayerGstElement *mainbin = NULL;
3917 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3918 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3920 mainbin = player->pipeline->mainbin;
3922 /* connect bus callback */
3923 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3925 LOGE("cannot get bus from pipeline");
3926 return MM_ERROR_PLAYER_INTERNAL;
3929 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3930 player->context.thread_default = g_main_context_get_thread_default();
3931 if (player->context.thread_default == NULL) {
3932 player->context.thread_default = g_main_context_default();
3933 LOGD("thread-default context is the global default context");
3935 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3937 /* set sync handler to get tag synchronously */
3938 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3939 gst_object_unref(GST_OBJECT(bus));
3941 /* create gst bus_msb_cb thread */
3942 g_mutex_init(&player->bus_msg_thread_mutex);
3943 g_cond_init(&player->bus_msg_thread_cond);
3944 player->bus_msg_thread_exit = FALSE;
3945 player->bus_msg_thread =
3946 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3947 if (!player->bus_msg_thread) {
3948 LOGE("failed to create gst BUS msg thread");
3949 g_mutex_clear(&player->bus_msg_thread_mutex);
3950 g_cond_clear(&player->bus_msg_thread_cond);
3951 return MM_ERROR_PLAYER_INTERNAL;
3955 return MM_ERROR_NONE;