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 = 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 g_free(new_string); \
729 mm_attrs_set_string_by_name(attribute, playertag, string); \
736 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
738 GstSample *sample = NULL;\
739 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
740 GstMapInfo info = GST_MAP_INFO_INIT;\
741 buffer = gst_sample_get_buffer(sample);\
742 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
743 LOGD("failed to get image data from tag");\
744 gst_sample_unref(sample);\
747 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
748 MMPLAYER_FREEIF(player->album_art);\
749 player->album_art = (gchar *)g_malloc(info.size);\
750 if (player->album_art) {\
751 memcpy(player->album_art, info.data, info.size);\
752 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
753 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
754 msg_param.data = (void *)player->album_art;\
755 msg_param.size = info.size;\
756 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
757 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
760 gst_buffer_unmap(buffer, &info);\
761 gst_sample_unref(sample);\
765 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
767 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
770 gchar *tag_list_str = NULL; \
771 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
772 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
773 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
774 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
775 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
777 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
778 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
779 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
780 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
781 player->bitrate[track_type] = v_uint; \
782 player->total_bitrate = 0; \
783 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
784 player->total_bitrate += player->bitrate[i]; \
785 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
786 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
787 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
788 player->maximum_bitrate[track_type] = v_uint; \
789 player->total_maximum_bitrate = 0; \
790 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
791 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
792 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
793 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
795 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
798 g_free(tag_list_str); \
803 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
804 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
806 string = g_strdup_printf("%d", g_date_get_year(date));\
807 mm_attrs_set_string_by_name(attribute, playertag, string);\
808 SECURE_LOGD("metainfo year : %s\n", string);\
809 MMPLAYER_FREEIF(string);\
814 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
815 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
816 if (datetime != NULL) {\
817 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
818 mm_attrs_set_string_by_name(attribute, playertag, string);\
819 SECURE_LOGD("metainfo year : %s\n", string);\
820 MMPLAYER_FREEIF(string);\
821 gst_date_time_unref(datetime);\
825 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
826 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
828 /* FIXIT : don't know how to store date */\
834 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
835 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
837 /* FIXIT : don't know how to store date */\
844 GstTagList* tag_list = NULL;
846 MMHandleType attrs = 0;
851 GstDateTime *datetime = NULL;
853 GstBuffer *buffer = NULL;
855 MMMessageParamType msg_param = {0, };
857 /* currently not used. but those are needed for above macro */
858 //guint64 v_uint64 = 0;
859 //gdouble v_double = 0;
861 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
863 attrs = MMPLAYER_GET_ATTRS(player);
865 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
867 /* get tag list from gst message */
868 gst_message_parse_tag(msg, &tag_list);
870 /* store tags to player attributes */
871 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
872 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
874 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
875 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
876 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
877 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
878 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
879 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
883 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
884 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
885 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
886 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
887 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
888 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
889 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
892 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
893 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
901 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
902 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
903 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
904 MMPLAYER_UPDATE_TAG_LOCK(player);
905 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
906 MMPLAYER_UPDATE_TAG_UNLOCK(player);
907 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
909 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
910 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
911 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
912 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
913 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
914 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
915 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
916 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
917 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
918 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
919 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
921 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
922 if (player->video360_metadata.is_spherical == -1) {
923 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
924 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
925 player->video360_metadata.is_spherical);
926 if (player->video360_metadata.is_spherical == 1) {
927 LOGD("This is spherical content for 360 playback.");
928 player->is_content_spherical = TRUE;
930 LOGD("This is not spherical content");
931 player->is_content_spherical = FALSE;
934 if (player->video360_metadata.projection_type_string) {
935 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
936 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
938 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
939 player->is_content_spherical = player->is_video360_enabled = FALSE;
943 if (player->video360_metadata.stereo_mode_string) {
944 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
945 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
946 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
947 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
948 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
949 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
951 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
952 player->is_content_spherical = player->is_video360_enabled = FALSE;
958 if (mm_attrs_commit_all(attrs))
959 LOGE("failed to commit.\n");
961 gst_tag_list_unref(tag_list);
966 /* if retval is FALSE, it will be dropped for perfomance. */
968 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
970 gboolean retval = FALSE;
972 if (!(player->pipeline && player->pipeline->mainbin)) {
973 LOGE("player pipeline handle is null");
977 switch (GST_MESSAGE_TYPE(message)) {
978 case GST_MESSAGE_TAG:
979 case GST_MESSAGE_EOS:
980 case GST_MESSAGE_ERROR:
981 case GST_MESSAGE_WARNING:
982 case GST_MESSAGE_CLOCK_LOST:
983 case GST_MESSAGE_NEW_CLOCK:
984 case GST_MESSAGE_ELEMENT:
985 case GST_MESSAGE_DURATION_CHANGED:
986 case GST_MESSAGE_ASYNC_START:
989 case GST_MESSAGE_ASYNC_DONE:
990 case GST_MESSAGE_STATE_CHANGED:
991 /* we only handle messages from pipeline */
992 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
997 case GST_MESSAGE_BUFFERING:
999 gint buffer_percent = 0;
1002 gst_message_parse_buffering(message, &buffer_percent);
1003 if (buffer_percent != MAX_BUFFER_PERCENT) {
1004 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1008 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1009 LOGW("can't get cmd lock, send msg to bus");
1013 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1014 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1015 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1018 MMPLAYER_CMD_UNLOCK(player);
1031 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1033 MMHandleType attrs = 0;
1034 guint64 data_size = 0;
1036 gint64 pos_nsec = 0;
1039 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1041 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1043 attrs = MMPLAYER_GET_ATTRS(player);
1045 LOGE("fail to get attributes.\n");
1049 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1050 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1052 if (stat(path, &sb) == 0)
1053 data_size = (guint64)sb.st_size;
1054 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1055 data_size = player->http_content_size;
1058 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1059 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1065 __mmplayer_handle_buffering_playback(mm_player_t* player)
1067 int ret = MM_ERROR_NONE;
1068 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1069 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1070 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1071 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1073 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1074 LOGW("do nothing for buffering msg\n");
1075 ret = MM_ERROR_PLAYER_INVALID_STATE;
1079 prev_state = MMPLAYER_PREV_STATE(player);
1080 current_state = MMPLAYER_CURRENT_STATE(player);
1081 target_state = MMPLAYER_TARGET_STATE(player);
1082 pending_state = MMPLAYER_PENDING_STATE(player);
1084 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1085 MMPLAYER_STATE_GET_NAME(prev_state),
1086 MMPLAYER_STATE_GET_NAME(current_state),
1087 MMPLAYER_STATE_GET_NAME(pending_state),
1088 MMPLAYER_STATE_GET_NAME(target_state),
1089 player->streamer->buffering_state);
1091 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1092 /* NOTE : if buffering has done, player has to go to target state. */
1093 switch (target_state) {
1094 case MM_PLAYER_STATE_PAUSED:
1096 switch (pending_state) {
1097 case MM_PLAYER_STATE_PLAYING:
1098 __mmplayer_gst_pause(player, TRUE);
1101 case MM_PLAYER_STATE_PAUSED:
1102 LOGD("player is already going to paused state, there is nothing to do.\n");
1105 case MM_PLAYER_STATE_NONE:
1106 case MM_PLAYER_STATE_NULL:
1107 case MM_PLAYER_STATE_READY:
1109 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1115 case MM_PLAYER_STATE_PLAYING:
1117 switch (pending_state) {
1118 case MM_PLAYER_STATE_NONE:
1120 if (current_state != MM_PLAYER_STATE_PLAYING)
1121 __mmplayer_gst_resume(player, TRUE);
1125 case MM_PLAYER_STATE_PAUSED:
1126 /* NOTE: It should be worked as asynchronously.
1127 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1129 if (current_state == MM_PLAYER_STATE_PLAYING) {
1130 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1131 * The current state should be changed to paused purposely to prevent state conflict.
1133 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1135 __mmplayer_gst_resume(player, TRUE);
1138 case MM_PLAYER_STATE_PLAYING:
1139 LOGD("player is already going to playing state, there is nothing to do.\n");
1142 case MM_PLAYER_STATE_NULL:
1143 case MM_PLAYER_STATE_READY:
1145 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1151 case MM_PLAYER_STATE_NULL:
1152 case MM_PLAYER_STATE_READY:
1153 case MM_PLAYER_STATE_NONE:
1155 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1159 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1160 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1162 switch (pending_state) {
1163 case MM_PLAYER_STATE_NONE:
1165 if (current_state != MM_PLAYER_STATE_PAUSED) {
1166 /* rtsp streaming pause makes rtsp server stop sending data. */
1167 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1168 LOGD("set pause state during buffering\n");
1169 __mmplayer_gst_pause(player, TRUE);
1175 case MM_PLAYER_STATE_PLAYING:
1176 /* rtsp streaming pause makes rtsp server stop sending data. */
1177 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1178 __mmplayer_gst_pause(player, TRUE);
1181 case MM_PLAYER_STATE_PAUSED:
1184 case MM_PLAYER_STATE_NULL:
1185 case MM_PLAYER_STATE_READY:
1187 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1196 static VariantData *
1197 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1199 VariantData *var_info = NULL;
1200 g_return_val_if_fail(self != NULL, NULL);
1202 var_info = g_new0(VariantData, 1);
1203 if (!var_info) return NULL;
1204 var_info->bandwidth = self->bandwidth;
1205 var_info->width = self->width;
1206 var_info->height = self->height;
1211 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1217 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1218 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1220 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1221 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1222 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1224 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1225 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1226 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1229 /* handling audio clip which has vbr. means duration is keep changing */
1230 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1239 __mmplayer_eos_timer_cb(gpointer u_data)
1241 mm_player_t* player = NULL;
1242 MMHandleType attrs = 0;
1245 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1247 player = (mm_player_t*) u_data;
1248 attrs = MMPLAYER_GET_ATTRS(player);
1250 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1254 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1255 if (ret_value != MM_ERROR_NONE)
1256 LOGE("seeking to 0 failed in repeat play");
1259 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1262 /* we are returning FALSE as we need only one posting */
1267 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1269 MMPLAYER_RETURN_IF_FAIL(player);
1271 /* post now if delay is zero */
1272 if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1273 LOGD("eos delay is zero. posting EOS now\n");
1274 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1276 if (player->audio_stream_render_cb)
1277 __mmplayer_cancel_eos_timer(player);
1282 /* cancel if existing */
1283 __mmplayer_cancel_eos_timer(player);
1285 /* init new timeout */
1286 /* NOTE : consider give high priority to this timer */
1287 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1289 player->eos_timer = g_timeout_add(delay_in_ms,
1290 __mmplayer_eos_timer_cb, player);
1292 player->context.global_default = g_main_context_default();
1293 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1295 /* check timer is valid. if not, send EOS now */
1296 if (player->eos_timer == 0) {
1297 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1298 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1302 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1304 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1305 int ret = MM_ERROR_NONE;
1309 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1311 if (!player->pending_seek.is_pending) {
1312 LOGD("pending seek is not reserved. nothing to do.\n");
1316 /* check player state if player could pending seek or not. */
1317 current_state = MMPLAYER_CURRENT_STATE(player);
1319 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1320 LOGW("try to pending seek in %s state, try next time. \n",
1321 MMPLAYER_STATE_GET_NAME(current_state));
1325 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1327 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1329 if (MM_ERROR_NONE != ret)
1330 LOGE("failed to seek pending postion. just keep staying current position.\n");
1332 player->pending_seek.is_pending = FALSE;
1340 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1342 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1344 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1346 audiobin = player->pipeline->audiobin; /* can be null */
1347 videobin = player->pipeline->videobin; /* can be null */
1348 textbin = player->pipeline->textbin; /* can be null */
1350 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1352 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1353 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1355 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1356 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1358 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1359 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1365 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1367 MMPlayerGstElement *textbin;
1370 MMPLAYER_RETURN_IF_FAIL(player &&
1372 player->pipeline->textbin);
1374 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1376 textbin = player->pipeline->textbin;
1379 LOGD("Drop subtitle text after getting EOS\n");
1381 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1382 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1384 player->is_subtitle_force_drop = TRUE;
1386 if (player->is_subtitle_force_drop == TRUE) {
1387 LOGD("Enable subtitle data path without drop\n");
1389 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1390 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1392 LOGD("non-connected with external display");
1394 player->is_subtitle_force_drop = FALSE;
1400 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1402 MMHandleType attrs = 0;
1407 /* NOTE : EOS event is comming multiple time. watch out it */
1408 /* check state. we only process EOS when pipeline state goes to PLAYING */
1409 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1410 LOGD("EOS received on non-playing state. ignoring it");
1414 if (player->pipeline && player->pipeline->textbin)
1415 __mmplayer_drop_subtitle(player, TRUE);
1417 if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1418 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1420 /* rewind if repeat count is greater then zero */
1421 /* get play count */
1422 attrs = MMPLAYER_GET_ATTRS(player);
1425 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1427 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1429 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1430 if (player->playback_rate < 0.0) {
1431 player->resumed_by_rewind = TRUE;
1432 _mmplayer_set_mute((MMHandleType)player, 0);
1433 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1436 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1439 player->sent_bos = FALSE;
1441 LOGD("do not post eos msg for repeating");
1446 if (player->pipeline)
1447 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1449 /* post eos message to application */
1450 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1452 /* reset last position */
1453 player->last_position = 0;
1460 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1462 GError *error = NULL;
1463 gchar* debug = NULL;
1467 /* generating debug info before returning error */
1468 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1470 /* get error code */
1471 gst_message_parse_error(msg, &error, &debug);
1473 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1474 /* Note : the streaming error from the streaming source is handled
1475 * using __mmplayer_handle_streaming_error.
1477 __mmplayer_handle_streaming_error(player, msg);
1479 /* dump state of all element */
1480 __mmplayer_dump_pipeline_state(player);
1482 /* traslate gst error code to msl error code. then post it
1483 * to application if needed
1485 __mmplayer_handle_gst_error(player, msg, error);
1488 LOGE("error debug : %s", debug);
1491 MMPLAYER_FREEIF(debug);
1492 g_error_free(error);
1499 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1501 MMMessageParamType msg_param = {0, };
1502 int bRet = MM_ERROR_NONE;
1505 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1507 if (!MMPLAYER_IS_STREAMING(player)) {
1508 LOGW("this is not streaming playback.");
1512 MMPLAYER_CMD_LOCK(player);
1514 if (!player->streamer) {
1515 LOGW("Pipeline is shutting down");
1516 MMPLAYER_CMD_UNLOCK(player);
1520 /* ignore the remained buffering message till getting 100% msg */
1521 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1522 gint buffer_percent = 0;
1524 gst_message_parse_buffering(msg, &buffer_percent);
1526 if (buffer_percent == MAX_BUFFER_PERCENT) {
1527 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1528 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1530 MMPLAYER_CMD_UNLOCK(player);
1534 /* ignore the remained buffering message */
1535 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1536 gint buffer_percent = 0;
1538 gst_message_parse_buffering(msg, &buffer_percent);
1540 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1541 player->streamer->buffering_percent, buffer_percent);
1543 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1544 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1545 player->streamer->buffering_req.is_pre_buffering = FALSE;
1547 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1549 LOGD("interrupted buffering - ignored the remained buffering msg!");
1550 MMPLAYER_CMD_UNLOCK(player);
1555 __mmplayer_update_buffer_setting(player, msg);
1557 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1559 if (bRet == MM_ERROR_NONE) {
1560 msg_param.connection.buffering = player->streamer->buffering_percent;
1561 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1563 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1564 player->pending_resume &&
1565 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1567 player->is_external_subtitle_added_now = FALSE;
1568 player->pending_resume = FALSE;
1569 _mmplayer_resume((MMHandleType)player);
1572 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1573 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1575 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1576 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1577 player->seek_state = MMPLAYER_SEEK_NONE;
1578 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1579 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1580 /* Considering the async state trasition in case of RTSP.
1581 After getting state change gst msg, seek cmpleted msg will be posted. */
1582 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1586 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1587 if (!player->streamer) {
1588 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1589 MMPLAYER_CMD_UNLOCK(player);
1593 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1595 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1596 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1598 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1599 msg_param.connection.buffering = player->streamer->buffering_percent;
1600 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1602 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1605 msg_param.connection.buffering = player->streamer->buffering_percent;
1606 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1609 MMPLAYER_CMD_UNLOCK(player);
1617 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1619 MMPlayerGstElement *mainbin;
1620 const GValue *voldstate, *vnewstate, *vpending;
1621 GstState oldstate = GST_STATE_NULL;
1622 GstState newstate = GST_STATE_NULL;
1623 GstState pending = GST_STATE_NULL;
1626 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1628 mainbin = player->pipeline->mainbin;
1630 /* we only handle messages from pipeline */
1631 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1634 /* get state info from msg */
1635 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1636 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1637 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1639 if (!voldstate || !vnewstate) {
1640 LOGE("received msg has wrong format.");
1644 oldstate = (GstState)voldstate->data[0].v_int;
1645 newstate = (GstState)vnewstate->data[0].v_int;
1647 pending = (GstState)vpending->data[0].v_int;
1649 LOGD("state changed [%s] : %s ---> %s final : %s",
1650 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1651 gst_element_state_get_name((GstState)oldstate),
1652 gst_element_state_get_name((GstState)newstate),
1653 gst_element_state_get_name((GstState)pending));
1655 if (newstate == GST_STATE_PLAYING) {
1656 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1658 int retVal = MM_ERROR_NONE;
1659 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1661 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1663 if (MM_ERROR_NONE != retVal)
1664 LOGE("failed to seek pending postion. just keep staying current position.");
1666 player->pending_seek.is_pending = FALSE;
1670 if (oldstate == newstate) {
1671 LOGD("pipeline reports state transition to old state");
1676 case GST_STATE_PAUSED:
1678 gboolean prepare_async = FALSE;
1680 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1681 // managed prepare async case
1682 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1683 LOGD("checking prepare mode for async transition - %d", prepare_async);
1686 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1687 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1689 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1690 __mm_player_streaming_set_content_bitrate(player->streamer,
1691 player->total_maximum_bitrate, player->total_bitrate);
1693 if (player->pending_seek.is_pending) {
1694 LOGW("trying to do pending seek");
1695 MMPLAYER_CMD_LOCK(player);
1696 __mmplayer_gst_pending_seek(player);
1697 MMPLAYER_CMD_UNLOCK(player);
1703 case GST_STATE_PLAYING:
1705 if (MMPLAYER_IS_STREAMING(player)) {
1706 // managed prepare async case when buffering is completed
1707 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1708 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1709 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1710 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1712 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1714 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1715 if (player->streamer->buffering_percent < 100) {
1717 MMMessageParamType msg_param = {0, };
1718 LOGW("Posting Buffering Completed Message to Application !!!");
1720 msg_param.connection.buffering = 100;
1721 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1726 if (player->gapless.stream_changed) {
1727 __mmplayer_update_content_attrs(player, ATTR_ALL);
1728 player->gapless.stream_changed = FALSE;
1731 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1732 player->seek_state = MMPLAYER_SEEK_NONE;
1733 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1737 case GST_STATE_VOID_PENDING:
1738 case GST_STATE_NULL:
1739 case GST_STATE_READY:
1749 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1751 const gchar *structure_name;
1752 gint count = 0, idx = 0;
1753 MMHandleType attrs = 0;
1756 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1758 attrs = MMPLAYER_GET_ATTRS(player);
1760 LOGE("Failed to get content attribute");
1764 if (gst_message_get_structure(msg) == NULL)
1767 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1768 if (!structure_name)
1771 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1773 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1774 const GValue *var_info = NULL;
1776 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1777 if (var_info != NULL) {
1778 if (player->adaptive_info.var_list)
1779 g_list_free_full(player->adaptive_info.var_list, g_free);
1781 /* share addr or copy the list */
1782 player->adaptive_info.var_list =
1783 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1785 count = g_list_length(player->adaptive_info.var_list);
1787 VariantData *temp = NULL;
1789 /* print out for debug */
1790 LOGD("num of variant_info %d", count);
1791 for (idx = 0; idx < count; idx++) {
1792 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1794 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1800 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1801 gint num_buffers = 0;
1802 gint extra_num_buffers = 0;
1804 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1805 player->video_num_buffers = num_buffers;
1806 LOGD("video_num_buffers : %d", player->video_num_buffers);
1809 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1810 player->video_extra_num_buffers = extra_num_buffers;
1811 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1816 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1817 __mmplayer_track_update_text_attr_info(player, msg);
1819 /* custom message */
1820 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1821 MMMessageParamType msg_param = {0,};
1822 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1823 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1826 /* custom message for RTSP attribute :
1827 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1828 sdp which has contents info is received when rtsp connection is opened.
1829 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1830 if (!strcmp(structure_name, "rtspsrc_properties")) {
1832 gchar *audio_codec = NULL;
1833 gchar *video_codec = NULL;
1834 gchar *video_frame_size = NULL;
1836 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1837 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1838 player->streaming_type = __mmplayer_get_stream_service_type(player);
1840 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1841 LOGD("rtsp_audio_codec : %s", audio_codec);
1843 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1845 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1846 LOGD("rtsp_video_codec : %s", video_codec);
1848 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1850 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1851 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1852 if (video_frame_size) {
1854 char *seperator = strchr(video_frame_size, '-');
1857 char video_width[10] = {0,};
1858 int frame_size_len = strlen(video_frame_size);
1859 int separtor_len = strlen(seperator);
1861 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1862 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1865 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1869 if (mm_attrs_commit_all(attrs))
1870 LOGE("failed to commit.");
1878 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1880 MMPlayerGstElement *mainbin;
1883 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1885 mainbin = player->pipeline->mainbin;
1887 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1889 /* we only handle messages from pipeline */
1890 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1893 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1894 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1895 player->seek_state = MMPLAYER_SEEK_NONE;
1896 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1897 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1898 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1899 LOGD("sync %s state(%s) with parent state(%s)",
1900 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1901 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1902 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1904 /* In case of streaming, pause is required before finishing seeking by buffering.
1905 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1906 Because the buffering state is controlled according to the state transition for force resume,
1907 the decodebin state should be paused as player state. */
1908 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1911 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1912 (player->streamer) &&
1913 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1914 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1915 GstQuery *query = NULL;
1916 gboolean busy = FALSE;
1919 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1920 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1921 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1922 gst_query_parse_buffering_percent(query, &busy, &percent);
1923 gst_query_unref(query);
1925 LOGD("buffered percent(%s): %d\n",
1926 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1930 __mmplayer_handle_buffering_playback(player);
1933 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1942 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1944 mm_player_t* player = (mm_player_t*)(data);
1946 MMPLAYER_RETURN_IF_FAIL(player);
1947 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1949 switch (GST_MESSAGE_TYPE(msg)) {
1950 case GST_MESSAGE_UNKNOWN:
1951 LOGD("unknown message received\n");
1954 case GST_MESSAGE_EOS:
1955 LOGD("GST_MESSAGE_EOS received");
1956 __mmplayer_gst_handle_eos_message(player, msg);
1959 case GST_MESSAGE_ERROR:
1960 __mmplayer_gst_handle_error_message(player, msg);
1963 case GST_MESSAGE_WARNING:
1966 GError* error = NULL;
1968 gst_message_parse_warning(msg, &error, &debug);
1970 LOGD("warning : %s\n", error->message);
1971 LOGD("debug : %s\n", debug);
1973 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1975 MMPLAYER_FREEIF(debug);
1976 g_error_free(error);
1980 case GST_MESSAGE_TAG:
1982 LOGD("GST_MESSAGE_TAG\n");
1983 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1984 LOGW("failed to extract tags from gstmessage\n");
1988 case GST_MESSAGE_BUFFERING:
1989 __mmplayer_gst_handle_buffering_message(player, msg);
1992 case GST_MESSAGE_STATE_CHANGED:
1993 __mmplayer_gst_handle_state_message(player, msg);
1996 case GST_MESSAGE_CLOCK_LOST:
1998 GstClock *clock = NULL;
1999 gboolean need_new_clock = FALSE;
2001 gst_message_parse_clock_lost(msg, &clock);
2002 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2004 if (!player->videodec_linked)
2005 need_new_clock = TRUE;
2006 else if (!player->ini.use_system_clock)
2007 need_new_clock = TRUE;
2009 if (need_new_clock) {
2010 LOGD("Provide clock is TRUE, do pause->resume\n");
2011 __mmplayer_gst_pause(player, FALSE);
2012 __mmplayer_gst_resume(player, FALSE);
2017 case GST_MESSAGE_NEW_CLOCK:
2019 GstClock *clock = NULL;
2020 gst_message_parse_new_clock(msg, &clock);
2021 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2025 case GST_MESSAGE_ELEMENT:
2026 __mmplayer_gst_handle_element_message(player, msg);
2029 case GST_MESSAGE_DURATION_CHANGED:
2031 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2032 if (!__mmplayer_gst_handle_duration(player, msg))
2033 LOGW("failed to update duration");
2037 case GST_MESSAGE_ASYNC_START:
2038 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2041 case GST_MESSAGE_ASYNC_DONE:
2042 __mmplayer_gst_handle_async_done_message(player, msg);
2045 #if 0 /* delete unnecessary logs */
2046 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2047 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2048 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2049 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2050 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2051 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2052 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2053 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2054 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2055 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2056 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2057 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2058 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2059 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2060 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2067 /* should not call 'gst_message_unref(msg)' */
2071 static GstBusSyncReply
2072 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2074 mm_player_t *player = (mm_player_t *)data;
2075 GstBusSyncReply reply = GST_BUS_DROP;
2077 if (!(player->pipeline && player->pipeline->mainbin)) {
2078 LOGE("player pipeline handle is null");
2079 return GST_BUS_PASS;
2082 if (!__mmplayer_gst_check_useful_message(player, message)) {
2083 gst_message_unref(message);
2084 return GST_BUS_DROP;
2087 switch (GST_MESSAGE_TYPE(message)) {
2088 case GST_MESSAGE_TAG:
2089 __mmplayer_gst_extract_tag_from_msg(player, message);
2093 GstTagList *tags = NULL;
2095 gst_message_parse_tag(message, &tags);
2097 LOGE("TAGS received from element \"%s\".\n",
2098 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2100 gst_tag_list_foreach(tags, print_tag, NULL);
2101 gst_tag_list_unref(tags);
2109 case GST_MESSAGE_DURATION_CHANGED:
2110 __mmplayer_gst_handle_duration(player, message);
2112 case GST_MESSAGE_ASYNC_DONE:
2113 /* NOTE:Don't call gst_callback directly
2114 * because previous frame can be showed even though this message is received for seek.
2117 reply = GST_BUS_PASS;
2121 if (reply == GST_BUS_DROP)
2122 gst_message_unref(message);
2128 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2130 GstElement *appsrc = element;
2131 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2132 GstBuffer *buffer = NULL;
2133 GstFlowReturn ret = GST_FLOW_OK;
2136 MMPLAYER_RETURN_IF_FAIL(element);
2137 MMPLAYER_RETURN_IF_FAIL(buf);
2139 buffer = gst_buffer_new();
2141 if (buf->offset < 0 || buf->len < 0) {
2142 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2146 if (buf->offset >= buf->len) {
2147 LOGD("call eos appsrc");
2148 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2152 if (buf->len - buf->offset < size)
2153 len = buf->len - buf->offset;
2155 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2156 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2157 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2159 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2160 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2166 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2168 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2170 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2172 buf->offset = (int)size;
2178 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2180 mm_player_t *player = (mm_player_t*)user_data;
2181 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2182 guint64 current_level_bytes = 0;
2184 MMPLAYER_RETURN_IF_FAIL(player);
2186 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2187 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2188 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2189 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2190 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2191 type = MM_PLAYER_STREAM_TYPE_TEXT;
2193 LOGE("can not enter here");
2197 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2199 LOGI("type: %d, level: %llu", type, current_level_bytes);
2201 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2202 if (player->media_stream_buffer_status_cb[type])
2203 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2204 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2208 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2210 mm_player_t *player = (mm_player_t*)user_data;
2211 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2212 guint64 current_level_bytes = 0;
2214 MMPLAYER_RETURN_IF_FAIL(player);
2216 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2217 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2218 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2219 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2220 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2221 type = MM_PLAYER_STREAM_TYPE_TEXT;
2223 LOGE("can not enter here");
2227 LOGI("type: %d, buffer is full", type);
2229 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2231 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2233 if (player->media_stream_buffer_status_cb[type])
2234 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2236 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2240 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2242 mm_player_t *player = (mm_player_t*)user_data;
2243 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2245 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2247 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2248 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2249 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2250 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2251 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2252 type = MM_PLAYER_STREAM_TYPE_TEXT;
2254 LOGE("can not enter here");
2258 LOGD("type: %d, pos: %llu", type, position);
2259 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2261 if (player->media_stream_seek_data_cb[type])
2262 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2263 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2269 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2271 #define MAX_LEN_NAME 20
2273 gboolean ret = FALSE;
2274 GstPad *sinkpad = NULL;
2275 gchar *prefix = NULL;
2276 gchar dec_name[MAX_LEN_NAME] = {0};
2277 enum MainElementID elem_id = MMPLAYER_M_NUM;
2279 MMPlayerGstElement *mainbin = NULL;
2280 GstElement *decodebin = NULL;
2281 GstCaps *dec_caps = NULL;
2285 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2287 player->pipeline->mainbin, FALSE);
2288 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2290 mainbin = player->pipeline->mainbin;
2292 case MM_PLAYER_STREAM_TYPE_AUDIO:
2294 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2296 case MM_PLAYER_STREAM_TYPE_VIDEO:
2298 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2301 LOGE("invalid type %d", type);
2305 if (mainbin[elem_id].gst) {
2306 LOGE("elem(%d) is already created", elem_id);
2310 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2312 /* create decodebin */
2313 decodebin = gst_element_factory_make("decodebin", dec_name);
2315 LOGE("failed to create %s", dec_name);
2319 mainbin[elem_id].id = elem_id;
2320 mainbin[elem_id].gst = decodebin;
2322 /* raw pad handling signal */
2323 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2324 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2326 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2327 before looking for any elements that can handle that stream.*/
2328 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2329 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2331 /* This signal is emitted when a element is added to the bin.*/
2332 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2333 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2335 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2336 LOGE("failed to add new decodebin");
2340 dec_caps = gst_pad_query_caps(srcpad, NULL);
2342 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2343 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2344 gst_caps_unref(dec_caps);
2347 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2349 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2350 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2353 gst_object_unref(GST_OBJECT(sinkpad));
2355 gst_element_sync_state_with_parent(decodebin);
2361 gst_object_unref(GST_OBJECT(sinkpad));
2363 if (mainbin[elem_id].gst) {
2364 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2365 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2366 gst_object_unref(mainbin[elem_id].gst);
2367 mainbin[elem_id].gst = NULL;
2375 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2377 #define MAX_LEN_NAME 20
2378 MMPlayerGstElement *mainbin = NULL;
2379 gchar *prefix = NULL;
2380 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2382 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2383 GstElement *src = NULL, *queue = NULL;
2384 GstPad *srcpad = NULL;
2387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2388 player->pipeline->mainbin, FALSE);
2390 mainbin = player->pipeline->mainbin;
2392 LOGD("type(%d) path is creating", type);
2394 case MM_PLAYER_STREAM_TYPE_AUDIO:
2396 if (mainbin[MMPLAYER_M_SRC].gst)
2397 src_id = MMPLAYER_M_2ND_SRC;
2399 src_id = MMPLAYER_M_SRC;
2400 queue_id = MMPLAYER_M_A_BUFFER;
2402 case MM_PLAYER_STREAM_TYPE_VIDEO:
2404 src_id = MMPLAYER_M_SRC;
2405 queue_id = MMPLAYER_M_V_BUFFER;
2407 case MM_PLAYER_STREAM_TYPE_TEXT:
2408 prefix = "subtitle";
2409 src_id = MMPLAYER_M_SUBSRC;
2410 queue_id = MMPLAYER_M_S_BUFFER;
2413 LOGE("invalid type %d", type);
2417 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2418 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2421 src = gst_element_factory_make("appsrc", src_name);
2423 LOGF("failed to create %s", src_name);
2427 mainbin[src_id].id = src_id;
2428 mainbin[src_id].gst = src;
2430 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2431 "caps", caps, NULL);
2433 /* size of many video frames are larger than default blocksize as 4096 */
2434 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2435 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2437 if (player->media_stream_buffer_max_size[type] > 0)
2438 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2440 if (player->media_stream_buffer_min_percent[type] > 0)
2441 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2443 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2444 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2446 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2447 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2448 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2449 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2450 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2451 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2454 queue = gst_element_factory_make("queue2", queue_name);
2456 LOGE("failed to create %s", queue_name);
2459 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2461 mainbin[queue_id].id = queue_id;
2462 mainbin[queue_id].gst = queue;
2464 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2465 LOGE("failed to add src");
2469 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2470 LOGE("failed to add queue");
2474 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2475 LOGE("failed to link src and queue");
2479 /* create decoder */
2480 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2482 LOGE("failed to get srcpad of queue");
2486 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2487 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2489 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2490 LOGE("failed to create decoder");
2491 gst_object_unref(GST_OBJECT(srcpad));
2495 gst_object_unref(GST_OBJECT(srcpad));
2499 if (mainbin[src_id].gst) {
2500 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2501 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2502 gst_object_unref(mainbin[src_id].gst);
2503 mainbin[src_id].gst = NULL;
2506 if (mainbin[queue_id].gst) {
2507 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2508 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2509 gst_object_unref(mainbin[queue_id].gst);
2510 mainbin[queue_id].gst = NULL;
2517 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2519 GstPad *sinkpad = NULL;
2520 GstCaps *caps = NULL;
2521 GstElement *new_element = NULL;
2522 GstStructure *str = NULL;
2523 const gchar *name = NULL;
2525 mm_player_t *player = (mm_player_t*) data;
2529 MMPLAYER_RETURN_IF_FAIL(element && pad);
2530 MMPLAYER_RETURN_IF_FAIL(player &&
2532 player->pipeline->mainbin);
2534 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2535 * num_dynamic_pad will decreased after creating a sinkbin.
2537 player->num_dynamic_pad++;
2538 LOGD("stream count inc : %d", player->num_dynamic_pad);
2540 caps = gst_pad_query_caps(pad, NULL);
2541 MMPLAYER_CHECK_NULL(caps);
2543 str = gst_caps_get_structure (caps, 0);
2544 name = gst_structure_get_string(str, "media");
2546 LOGE("cannot get mimetype from structure.\n");
2550 if (strstr(name, "video")) {
2552 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2554 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2555 if (player->v_stream_caps) {
2556 gst_caps_unref(player->v_stream_caps);
2557 player->v_stream_caps = NULL;
2560 new_element = gst_element_factory_make("fakesink", NULL);
2561 player->num_dynamic_pad--;
2566 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2567 LOGE("failed to autoplug for caps");
2571 gst_caps_unref(caps);
2576 /* excute new_element if created*/
2578 LOGD("adding new element to pipeline\n");
2580 /* set state to READY before add to bin */
2581 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2583 /* add new element to the pipeline */
2584 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2585 LOGE("failed to add autoplug element to bin\n");
2589 /* get pad from element */
2590 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2592 LOGE("failed to get sinkpad from autoplug element\n");
2597 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2598 LOGE("failed to link autoplug element\n");
2602 gst_object_unref(sinkpad);
2605 /* run. setting PLAYING here since streamming source is live source */
2606 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2610 gst_caps_unref(caps);
2616 STATE_CHANGE_FAILED:
2618 /* FIXIT : take care if new_element has already added to pipeline */
2620 gst_object_unref(GST_OBJECT(new_element));
2623 gst_object_unref(GST_OBJECT(sinkpad));
2626 gst_caps_unref(caps);
2628 /* FIXIT : how to inform this error to MSL ????? */
2629 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2630 * then post an error to application
2635 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2637 mm_player_t* player = (mm_player_t*) data;
2641 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2642 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2643 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2644 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2646 * [1] audio and video will be dumped with filesink.
2647 * [2] autoplugging is done by just using pad caps.
2648 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2649 * and the video will be dumped via filesink.
2651 if (player->num_dynamic_pad == 0) {
2652 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2654 if (!__mmplayer_gst_remove_fakesink(player,
2655 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2656 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2657 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2658 * source element are not same. To overcome this situation, this function will called
2659 * several places and several times. Therefore, this is not an error case.
2664 /* create dot before error-return. for debugging */
2665 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2667 player->no_more_pad = TRUE;
2673 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2675 GstElement* element = NULL;
2676 gchar *user_agent = NULL;
2677 MMHandleType attrs = 0;
2680 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2682 /* get profile attribute */
2683 attrs = MMPLAYER_GET_ATTRS(player);
2685 LOGE("failed to get content attribute");
2689 element = gst_element_factory_make("rtspsrc", "rtsp source");
2691 LOGE("failed to create rtspsrc element");
2696 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2698 SECURE_LOGD("user_agent : %s", user_agent);
2700 /* setting property to streaming source */
2701 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2703 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2705 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2706 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2707 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2708 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2715 __mmplayer_gst_make_http_src(mm_player_t* player)
2717 GstElement* element = NULL;
2718 MMHandleType attrs = 0;
2719 gchar *user_agent, *cookies, **cookie_list;
2720 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2721 user_agent = cookies = NULL;
2725 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2727 /* get profile attribute */
2728 attrs = MMPLAYER_GET_ATTRS(player);
2730 LOGE("failed to get content attribute");
2734 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2736 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2738 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2743 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2744 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2746 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2747 http_timeout = player->ini.http_timeout;
2750 SECURE_LOGD("location : %s", player->profile.uri);
2751 SECURE_LOGD("cookies : %s", cookies);
2752 SECURE_LOGD("user_agent : %s", user_agent);
2753 LOGD("timeout : %d", http_timeout);
2755 /* setting property to streaming source */
2756 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2757 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2759 /* parsing cookies */
2760 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2761 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2762 g_strfreev(cookie_list);
2766 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2768 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2769 LOGW("[DASH] this is still experimental feature");
2776 __mmplayer_gst_make_file_src(mm_player_t* player)
2778 GstElement* element = NULL;
2781 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2783 LOGD("using filesrc for 'file://' handler");
2784 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2785 LOGE("failed to get storage info");
2789 element = gst_element_factory_make("filesrc", "source");
2791 LOGE("failed to create filesrc");
2795 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2801 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2803 mm_player_t *player = (mm_player_t *) data;
2805 g_return_val_if_fail(player, FALSE);
2806 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2808 gst_message_ref(msg);
2810 g_mutex_lock(&player->bus_msg_q_lock);
2811 g_queue_push_tail(player->bus_msg_q, msg);
2812 g_mutex_unlock(&player->bus_msg_q_lock);
2814 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2815 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2816 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2820 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2822 mm_player_t *player = (mm_player_t*)(data);
2823 GstMessage *msg = NULL;
2827 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2829 player->pipeline->mainbin &&
2830 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2833 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2835 LOGE("cannot get BUS from the pipeline");
2839 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2841 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2842 while (!player->bus_msg_thread_exit) {
2843 g_mutex_lock(&player->bus_msg_q_lock);
2844 msg = g_queue_pop_head(player->bus_msg_q);
2845 g_mutex_unlock(&player->bus_msg_q_lock);
2847 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2850 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2851 /* handle the gst msg */
2852 __mmplayer_gst_bus_msg_callback(msg, player);
2853 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2854 gst_message_unref(msg);
2857 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2858 gst_object_unref(GST_OBJECT(bus));
2865 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2867 gint64 dur_nsec = 0;
2870 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2872 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2873 return MM_ERROR_NONE;
2875 /* NOTE : duration cannot be zero except live streaming.
2876 * Since some element could have some timing problemn with quering duration, try again.
2878 if (player->duration == 0) {
2879 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2880 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2881 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2882 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2883 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2884 player->pending_seek.is_pending = TRUE;
2885 player->pending_seek.pos = position;
2886 player->seek_state = MMPLAYER_SEEK_NONE;
2887 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2888 return MM_ERROR_PLAYER_NO_OP;
2890 player->seek_state = MMPLAYER_SEEK_NONE;
2891 return MM_ERROR_PLAYER_SEEK;
2894 player->duration = dur_nsec;
2897 if (player->duration > 0 && player->duration < position) {
2898 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2899 return MM_ERROR_INVALID_ARGUMENT;
2903 return MM_ERROR_NONE;
2907 __mmplayer_gst_check_seekable(mm_player_t* player)
2909 GstQuery *query = NULL;
2910 gboolean seekable = FALSE;
2912 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2916 query = gst_query_new_seeking(GST_FORMAT_TIME);
2917 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2918 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2919 gst_query_unref(query);
2922 LOGW("non-seekable content");
2923 player->seek_state = MMPLAYER_SEEK_NONE;
2927 LOGW("failed to get seeking query");
2928 gst_query_unref(query); /* keep seeking operation */
2939 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2941 GstState element_state = GST_STATE_VOID_PENDING;
2942 GstState element_pending_state = GST_STATE_VOID_PENDING;
2943 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2947 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2948 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2950 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2953 ret = gst_element_set_state(element, state);
2955 if (ret == GST_STATE_CHANGE_FAILURE) {
2956 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2958 /* dump state of all element */
2959 __mmplayer_dump_pipeline_state(player);
2961 return MM_ERROR_PLAYER_INTERNAL;
2964 /* return here so state transition to be done in async mode */
2966 LOGD("async state transition. not waiting for state complete.\n");
2967 return MM_ERROR_NONE;
2970 /* wait for state transition */
2971 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2973 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2974 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
2975 GST_ELEMENT_NAME(element),
2976 gst_element_state_get_name(state), timeout);
2978 LOGE(" [%s] state : %s pending : %s \n",
2979 GST_ELEMENT_NAME(element),
2980 gst_element_state_get_name(element_state),
2981 gst_element_state_get_name(element_pending_state));
2983 /* dump state of all element */
2984 __mmplayer_dump_pipeline_state(player);
2986 return MM_ERROR_PLAYER_INTERNAL;
2989 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
2993 return MM_ERROR_NONE;
2996 int __mmplayer_gst_start(mm_player_t* player)
2998 int ret = MM_ERROR_NONE;
2999 gboolean async = FALSE;
3003 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3005 /* NOTE : if SetPosition was called before Start. do it now */
3006 /* streaming doesn't support it. so it should be always sync */
3007 /* !!create one more api to check if there is pending seek rather than checking variables */
3008 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3009 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3010 ret = __mmplayer_gst_pause(player, FALSE);
3011 if (ret != MM_ERROR_NONE) {
3012 LOGE("failed to set state to PAUSED for pending seek");
3016 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3017 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3018 LOGW("failed to seek pending postion. starting from the begin of content");
3021 LOGD("current state before doing transition");
3022 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3023 MMPLAYER_PRINT_STATE(player);
3025 /* set pipeline state to PLAYING */
3026 ret = __mmplayer_gst_set_state(player,
3027 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3029 if (ret == MM_ERROR_NONE) {
3030 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3032 LOGE("failed to set state to PLAYING");
3036 /* generating debug info before returning error */
3037 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3044 int __mmplayer_gst_stop(mm_player_t* player)
3046 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3047 MMHandleType attrs = 0;
3048 gboolean rewind = FALSE;
3050 int ret = MM_ERROR_NONE;
3054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3055 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3057 LOGD("current state before doing transition");
3058 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3059 MMPLAYER_PRINT_STATE(player);
3061 attrs = MMPLAYER_GET_ATTRS(player);
3063 LOGE("cannot get content attribute\n");
3064 return MM_ERROR_PLAYER_INTERNAL;
3067 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3068 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3070 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3071 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3074 if (player->es_player_push_mode) {
3075 /* disable the async state transition because there could be no data in the pipeline */
3076 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3080 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3082 if (player->es_player_push_mode) {
3083 /* enable the async state transition as default operation */
3084 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3087 /* return if set_state has failed */
3088 if (ret != MM_ERROR_NONE) {
3089 LOGE("failed to set state.\n");
3095 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3096 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3097 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3098 LOGW("failed to rewind\n");
3099 ret = MM_ERROR_PLAYER_SEEK;
3104 player->sent_bos = FALSE;
3106 if (player->es_player_push_mode) //for cloudgame
3109 /* wait for seek to complete */
3110 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3111 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3112 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3114 LOGE("fail to stop player.\n");
3115 ret = MM_ERROR_PLAYER_INTERNAL;
3116 __mmplayer_dump_pipeline_state(player);
3119 /* generate dot file if enabled */
3120 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3127 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3129 int ret = MM_ERROR_NONE;
3133 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3134 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3136 LOGD("current state before doing transition");
3137 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3138 MMPLAYER_PRINT_STATE(player);
3140 /* set pipeline status to PAUSED */
3141 ret = __mmplayer_gst_set_state(player,
3142 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3144 if (FALSE == async) {
3145 if (ret != MM_ERROR_NONE) {
3146 GstMessage *msg = NULL;
3147 GTimer *timer = NULL;
3148 gdouble MAX_TIMEOUT_SEC = 3;
3150 LOGE("failed to set state to PAUSED");
3152 if (!player->bus_watcher) {
3153 LOGE("there is no bus msg thread. pipeline is shutting down.");
3157 if (player->msg_posted) {
3158 LOGE("error msg is already posted.");
3162 timer = g_timer_new();
3163 g_timer_start(timer);
3165 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3168 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3170 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3171 GError *error = NULL;
3173 /* parse error code */
3174 gst_message_parse_error(msg, &error, NULL);
3176 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3177 /* Note : the streaming error from the streaming source is handled
3178 * using __mmplayer_handle_streaming_error.
3180 __mmplayer_handle_streaming_error(player, msg);
3183 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3185 if (error->domain == GST_STREAM_ERROR)
3186 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3187 else if (error->domain == GST_RESOURCE_ERROR)
3188 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3189 else if (error->domain == GST_LIBRARY_ERROR)
3190 ret = __mmplayer_gst_handle_library_error(player, error->code);
3191 else if (error->domain == GST_CORE_ERROR)
3192 ret = __mmplayer_gst_handle_core_error(player, error->code);
3194 g_error_free(error);
3196 player->msg_posted = TRUE;
3198 gst_message_unref(msg);
3200 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3202 gst_object_unref(bus);
3203 g_timer_stop(timer);
3204 g_timer_destroy(timer);
3208 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3209 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3211 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3214 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3218 /* generate dot file before returning error */
3219 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3226 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3228 int ret = MM_ERROR_NONE;
3233 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3234 MM_ERROR_PLAYER_NOT_INITIALIZED);
3236 LOGD("current state before doing transition");
3237 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3238 MMPLAYER_PRINT_STATE(player);
3241 LOGD("do async state transition to PLAYING");
3243 /* set pipeline state to PLAYING */
3244 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3246 ret = __mmplayer_gst_set_state(player,
3247 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3248 if (ret != MM_ERROR_NONE) {
3249 LOGE("failed to set state to PLAYING");
3253 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3257 /* generate dot file */
3258 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3265 /* sending event to one of sinkelements */
3267 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3269 GstEvent * event2 = NULL;
3270 GList *sinks = NULL;
3271 gboolean res = FALSE;
3274 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3275 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3277 /* While adding subtitles in live feeds seek is getting called.
3278 Adding defensive check in framework layer.*/
3279 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3280 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3281 LOGE("Should not send seek event during live playback");
3286 if (player->play_subtitle)
3287 event2 = gst_event_copy((const GstEvent *)event);
3289 sinks = player->sink_elements;
3291 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3293 if (GST_IS_ELEMENT(sink)) {
3294 /* keep ref to the event */
3295 gst_event_ref(event);
3297 if ((res = gst_element_send_event(sink, event))) {
3298 LOGD("sending event[%s] to sink element [%s] success!\n",
3299 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3301 /* rtsp case, asyn_done is not called after seek during pause state */
3302 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3303 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3304 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3305 LOGD("RTSP seek completed, after pause state..\n");
3306 player->seek_state = MMPLAYER_SEEK_NONE;
3307 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3313 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3314 sinks = g_list_next(sinks);
3321 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3322 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3325 sinks = g_list_next(sinks);
3328 /* Note : Textbin is not linked to the video or audio bin.
3329 * It needs to send the event to the text sink seperatelly.
3331 if (player->play_subtitle && player->pipeline) {
3332 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3334 if (GST_IS_ELEMENT(text_sink)) {
3335 /* keep ref to the event */
3336 gst_event_ref(event2);
3338 if ((res = gst_element_send_event(text_sink, event2)))
3339 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3340 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3342 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3343 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3345 gst_event_unref(event2);
3349 gst_event_unref(event);
3357 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3358 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3359 gint64 cur, GstSeekType stop_type, gint64 stop)
3361 GstEvent* event = NULL;
3362 gboolean result = FALSE;
3366 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3368 if (player->pipeline && player->pipeline->textbin)
3369 __mmplayer_drop_subtitle(player, FALSE);
3371 event = gst_event_new_seek(rate, format, flags, cur_type,
3372 cur, stop_type, stop);
3374 result = __mmplayer_gst_send_event_to_sink(player, event);
3382 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3384 int ret = MM_ERROR_NONE;
3385 gint64 pos_nsec = 0;
3386 gboolean accurated = FALSE;
3387 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3390 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3391 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3393 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3394 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3397 ret = __mmplayer_gst_check_duration(player, position);
3398 if (ret != MM_ERROR_NONE) {
3399 LOGE("failed to check duration 0x%X", ret);
3400 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3403 if (!__mmplayer_gst_check_seekable(player))
3404 return MM_ERROR_PLAYER_NO_OP;
3406 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3407 position, player->playback_rate, player->duration);
3409 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3410 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3411 This causes problem is position calculation during normal pause resume scenarios also.
3412 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3413 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3414 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3415 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3416 LOGW("getting current position failed in seek");
3418 player->last_position = pos_nsec;
3419 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3422 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3423 LOGD("not completed seek");
3424 return MM_ERROR_PLAYER_DOING_SEEK;
3427 if (!internal_called)
3428 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3430 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3431 that's why set position through property. */
3432 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3433 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3434 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3435 (!player->videodec_linked) && (!player->audiodec_linked)) {
3437 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3438 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3440 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3441 player->seek_state = MMPLAYER_SEEK_NONE;
3442 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3444 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3446 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3448 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3450 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3451 GST_FORMAT_TIME, seek_flags,
3452 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3453 LOGE("failed to set position");
3458 /* NOTE : store last seeking point to overcome some bad operation
3459 * (returning zero when getting current position) of some elements
3461 player->last_position = position;
3463 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3464 if (player->playback_rate > 1.0)
3465 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3467 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3468 LOGD("buffering should be reset after seeking");
3469 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3470 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3474 return MM_ERROR_NONE;
3477 player->pending_seek.is_pending = TRUE;
3478 player->pending_seek.pos = position;
3480 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3481 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3482 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3483 player->pending_seek.pos);
3485 return MM_ERROR_NONE;
3488 player->seek_state = MMPLAYER_SEEK_NONE;
3489 return MM_ERROR_PLAYER_SEEK;
3493 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3495 #define TRICKPLAY_OFFSET GST_MSECOND
3497 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3498 gint64 pos_nsec = 0;
3499 gboolean ret = TRUE;
3501 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3502 MM_ERROR_PLAYER_NOT_INITIALIZED);
3504 current_state = MMPLAYER_CURRENT_STATE(player);
3506 /* NOTE : query position except paused state to overcome some bad operation
3507 * please refer to below comments in details
3509 if (current_state != MM_PLAYER_STATE_PAUSED)
3510 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3512 /* NOTE : get last point to overcome some bad operation of some elements
3513 *(returning zero when getting current position in paused state
3514 * and when failed to get postion during seeking
3516 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3517 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3519 if (player->playback_rate < 0.0)
3520 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3522 pos_nsec = player->last_position;
3525 pos_nsec = player->last_position;
3527 player->last_position = pos_nsec;
3529 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3532 if (player->duration > 0 && pos_nsec > player->duration)
3533 pos_nsec = player->duration;
3535 player->last_position = pos_nsec;
3538 *position = pos_nsec;
3540 return MM_ERROR_NONE;
3543 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3545 #define STREAMING_IS_FINISHED 0
3546 #define BUFFERING_MAX_PER 100
3547 #define DEFAULT_PER_VALUE -1
3548 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3550 MMPlayerGstElement *mainbin = NULL;
3551 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3552 gint64 buffered_total = 0;
3553 gint64 position = 0;
3554 gint buffered_sec = -1;
3555 GstBufferingMode mode = GST_BUFFERING_STREAM;
3556 gint64 content_size_time = player->duration;
3557 guint64 content_size_bytes = player->http_content_size;
3559 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3561 player->pipeline->mainbin,
3562 MM_ERROR_PLAYER_NOT_INITIALIZED);
3564 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3569 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3570 /* and rtsp is not ready yet. */
3571 LOGW("it's only used for http streaming case");
3572 return MM_ERROR_PLAYER_NO_OP;
3575 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3576 LOGW("Time format is not supported yet");
3577 return MM_ERROR_INVALID_ARGUMENT;
3580 if (content_size_time <= 0 || content_size_bytes <= 0) {
3581 LOGW("there is no content size");
3582 return MM_ERROR_NONE;
3585 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3586 LOGW("fail to get current position");
3587 return MM_ERROR_NONE;
3590 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3591 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3593 mainbin = player->pipeline->mainbin;
3594 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3596 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3597 GstQuery *query = NULL;
3598 gint byte_in_rate = 0, byte_out_rate = 0;
3599 gint64 estimated_total = 0;
3601 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3602 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3603 LOGW("fail to get buffering query from queue2");
3605 gst_query_unref(query);
3606 return MM_ERROR_NONE;
3609 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3610 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3612 if (mode == GST_BUFFERING_STREAM) {
3613 /* using only queue in case of push mode(ts / mp3) */
3614 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3615 GST_FORMAT_BYTES, &buffered_total)) {
3616 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3617 stop_per = 100 * buffered_total / content_size_bytes;
3620 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3622 guint num_of_ranges = 0;
3623 gint64 start_byte = 0, stop_byte = 0;
3625 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3626 if (estimated_total != STREAMING_IS_FINISHED) {
3627 /* buffered size info from queue2 */
3628 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3629 for (idx = 0; idx < num_of_ranges; idx++) {
3630 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3631 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3633 buffered_total += (stop_byte - start_byte);
3636 stop_per = BUFFERING_MAX_PER;
3638 gst_query_unref(query);
3641 if (stop_per == DEFAULT_PER_VALUE) {
3642 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3644 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3646 /* buffered size info from multiqueue */
3647 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3648 guint curr_size_bytes = 0;
3649 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3650 "curr-size-bytes", &curr_size_bytes, NULL);
3651 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3652 buffered_total += curr_size_bytes;
3655 if (avg_byterate > 0)
3656 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3657 else if (player->total_maximum_bitrate > 0)
3658 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3659 else if (player->total_bitrate > 0)
3660 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3662 if (buffered_sec >= 0)
3663 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3667 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3668 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3670 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3671 buffered_total, buffered_sec, *start_pos, *stop_pos);
3673 return MM_ERROR_NONE;
3676 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3678 GstElement* element = NULL;
3681 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3682 player->pipeline->mainbin, NULL);
3684 /* setup source for gapless play */
3685 switch (player->profile.uri_type) {
3687 case MM_PLAYER_URI_TYPE_FILE:
3688 element = __mmplayer_gst_make_file_src(player);
3690 case MM_PLAYER_URI_TYPE_URL_HTTP:
3691 element = __mmplayer_gst_make_http_src(player);
3694 LOGE("not support uri type %d", player->profile.uri_type);
3699 LOGE("failed to create source element");
3707 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3709 MMHandleType attrs = 0;
3712 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3713 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3715 /* get profile attribute */
3716 attrs = MMPLAYER_GET_ATTRS(player);
3718 LOGE("failed to get content attribute");
3719 return MM_ERROR_PLAYER_INTERNAL;
3722 SECURE_LOGD("uri : %s", player->profile.uri);
3724 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3725 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3726 LOGE("failed to commit");
3728 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3729 return MM_ERROR_PLAYER_INTERNAL;
3731 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3732 return MM_ERROR_PLAYER_INTERNAL;
3734 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3735 return MM_ERROR_PLAYER_INTERNAL;
3738 return MM_ERROR_NONE;
3741 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3743 MMPlayerGstElement *mainbin = NULL;
3744 GstElement* src_elem = NULL;
3745 GstElement *autoplug_elem = NULL;
3746 GList* element_bucket = NULL;
3747 MMHandleType attrs = 0;
3748 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3751 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3752 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3754 /* get profile attribute */
3755 attrs = MMPLAYER_GET_ATTRS(player);
3757 LOGE("failed to get content attribute");
3758 return MM_ERROR_PLAYER_INTERNAL;
3761 LOGD("uri type %d", player->profile.uri_type);
3763 /* create source element */
3764 switch (player->profile.uri_type) {
3765 case MM_PLAYER_URI_TYPE_URL_RTSP:
3766 src_elem = __mmplayer_gst_make_rtsp_src(player);
3768 case MM_PLAYER_URI_TYPE_URL_HTTP:
3769 src_elem = __mmplayer_gst_make_http_src(player);
3771 case MM_PLAYER_URI_TYPE_FILE:
3772 src_elem = __mmplayer_gst_make_file_src(player);
3774 case MM_PLAYER_URI_TYPE_SS:
3776 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3777 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3779 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3783 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3784 LOGD("get timeout from ini");
3785 http_timeout = player->ini.http_timeout;
3788 /* setting property to streaming source */
3789 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3792 case MM_PLAYER_URI_TYPE_MEM:
3794 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3796 src_elem = gst_element_factory_make("appsrc", "mem-source");
3798 LOGE("failed to create appsrc element");
3802 g_object_set(src_elem, "stream-type", stream_type,
3803 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3805 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3806 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3807 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3808 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3812 LOGE("not support uri type");
3817 LOGE("failed to create source element");
3818 return MM_ERROR_PLAYER_INTERNAL;
3821 mainbin = player->pipeline->mainbin;
3823 /* take source element */
3824 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3826 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3827 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3828 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3830 /* create next element for auto-plugging */
3831 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3832 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3833 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3834 if (!autoplug_elem) {
3835 LOGE("failed to create typefind element");
3839 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3840 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3841 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3842 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3843 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3844 if (!autoplug_elem) {
3845 LOGE("failed to create decodebin");
3849 /* default size of mq in decodebin is 2M
3850 * but it can cause blocking issue during seeking depends on content. */
3851 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
3854 if (autoplug_elem) {
3855 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3856 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3857 mainbin[autoplug_elem_id].gst = autoplug_elem;
3859 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3862 /* add elements to pipeline */
3863 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3864 LOGE("failed to add elements to pipeline");
3868 /* linking elements in the bucket by added order. */
3869 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3870 LOGE("failed to link some elements");
3874 /* FIXME: need to check whether this is required or not. */
3875 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3876 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3877 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3878 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3880 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3881 LOGE("failed to create fakesink");
3884 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3886 /* take ownership of fakesink. we are reusing it */
3887 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3889 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3890 LOGE("failed to add fakesink to bin");
3891 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3896 g_list_free(element_bucket);
3899 return MM_ERROR_NONE;
3902 g_list_free(element_bucket);
3904 if (mainbin[MMPLAYER_M_SRC].gst)
3905 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3907 if (mainbin[autoplug_elem_id].gst)
3908 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3910 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3911 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3913 mainbin[MMPLAYER_M_SRC].gst = NULL;
3914 mainbin[autoplug_elem_id].gst = NULL;
3915 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3917 return MM_ERROR_PLAYER_INTERNAL;
3920 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
3923 MMPlayerGstElement *mainbin = NULL;
3926 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3927 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3929 mainbin = player->pipeline->mainbin;
3931 /* connect bus callback */
3932 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3934 LOGE("cannot get bus from pipeline");
3935 return MM_ERROR_PLAYER_INTERNAL;
3938 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3939 player->context.thread_default = g_main_context_get_thread_default();
3940 if (player->context.thread_default == NULL) {
3941 player->context.thread_default = g_main_context_default();
3942 LOGD("thread-default context is the global default context");
3944 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3946 /* set sync handler to get tag synchronously */
3947 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3948 gst_object_unref(GST_OBJECT(bus));
3950 /* create gst bus_msb_cb thread */
3951 g_mutex_init(&player->bus_msg_thread_mutex);
3952 g_cond_init(&player->bus_msg_thread_cond);
3953 player->bus_msg_thread_exit = FALSE;
3954 player->bus_msg_thread =
3955 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3956 if (!player->bus_msg_thread) {
3957 LOGE("failed to create gst BUS msg thread");
3958 g_mutex_clear(&player->bus_msg_thread_mutex);
3959 g_cond_clear(&player->bus_msg_thread_cond);
3960 return MM_ERROR_PLAYER_INTERNAL;
3964 return MM_ERROR_NONE;