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 if (MMPLAYER_IS_HTTP_PD(player))
1492 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1494 MMPLAYER_FREEIF(debug);
1495 g_error_free(error);
1502 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1504 MMMessageParamType msg_param = {0, };
1505 int bRet = MM_ERROR_NONE;
1508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1510 if (!MMPLAYER_IS_STREAMING(player)) {
1511 LOGW("this is not streaming playback.");
1515 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1516 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1517 /* skip the playback control by buffering msg while user request is handled. */
1520 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1522 gst_message_parse_buffering(msg, &per);
1523 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1525 msg_param.connection.buffering = per;
1526 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1530 MMPLAYER_CMD_LOCK(player);
1533 if (!player->streamer) {
1534 LOGW("Pipeline is shutting down");
1535 MMPLAYER_CMD_UNLOCK(player);
1539 /* ignore the remained buffering message till getting 100% msg */
1540 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1541 gint buffer_percent = 0;
1543 gst_message_parse_buffering(msg, &buffer_percent);
1545 if (buffer_percent == MAX_BUFFER_PERCENT) {
1546 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1547 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1549 MMPLAYER_CMD_UNLOCK(player);
1553 /* ignore the remained buffering message */
1554 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1555 gint buffer_percent = 0;
1557 gst_message_parse_buffering(msg, &buffer_percent);
1559 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1560 player->streamer->buffering_percent, buffer_percent);
1562 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1563 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1564 player->streamer->buffering_req.is_pre_buffering = FALSE;
1566 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1568 LOGD("interrupted buffering - ignored the remained buffering msg!");
1569 MMPLAYER_CMD_UNLOCK(player);
1574 __mmplayer_update_buffer_setting(player, msg);
1576 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1578 if (bRet == MM_ERROR_NONE) {
1579 msg_param.connection.buffering = player->streamer->buffering_percent;
1580 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1582 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1583 player->pending_resume &&
1584 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1586 player->is_external_subtitle_added_now = FALSE;
1587 player->pending_resume = FALSE;
1588 _mmplayer_resume((MMHandleType)player);
1591 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1592 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1594 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1595 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1596 player->seek_state = MMPLAYER_SEEK_NONE;
1597 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1598 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1599 /* Considering the async state trasition in case of RTSP.
1600 After getting state change gst msg, seek cmpleted msg will be posted. */
1601 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1605 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1606 if (!player->streamer) {
1607 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1608 MMPLAYER_CMD_UNLOCK(player);
1612 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1614 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1615 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1617 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1618 msg_param.connection.buffering = player->streamer->buffering_percent;
1619 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1621 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1624 msg_param.connection.buffering = player->streamer->buffering_percent;
1625 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1628 MMPLAYER_CMD_UNLOCK(player);
1636 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1638 MMPlayerGstElement *mainbin;
1639 const GValue *voldstate, *vnewstate, *vpending;
1640 GstState oldstate = GST_STATE_NULL;
1641 GstState newstate = GST_STATE_NULL;
1642 GstState pending = GST_STATE_NULL;
1645 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1647 mainbin = player->pipeline->mainbin;
1649 /* we only handle messages from pipeline */
1650 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1653 /* get state info from msg */
1654 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1655 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1656 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1658 if (!voldstate || !vnewstate) {
1659 LOGE("received msg has wrong format.");
1663 oldstate = (GstState)voldstate->data[0].v_int;
1664 newstate = (GstState)vnewstate->data[0].v_int;
1666 pending = (GstState)vpending->data[0].v_int;
1668 LOGD("state changed [%s] : %s ---> %s final : %s",
1669 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1670 gst_element_state_get_name((GstState)oldstate),
1671 gst_element_state_get_name((GstState)newstate),
1672 gst_element_state_get_name((GstState)pending));
1674 if (newstate == GST_STATE_PLAYING) {
1675 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1677 int retVal = MM_ERROR_NONE;
1678 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1680 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1682 if (MM_ERROR_NONE != retVal)
1683 LOGE("failed to seek pending postion. just keep staying current position.");
1685 player->pending_seek.is_pending = FALSE;
1689 if (oldstate == newstate) {
1690 LOGD("pipeline reports state transition to old state");
1695 case GST_STATE_PAUSED:
1697 gboolean prepare_async = FALSE;
1699 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1700 // managed prepare async case
1701 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1702 LOGD("checking prepare mode for async transition - %d", prepare_async);
1705 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1706 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1708 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1709 __mm_player_streaming_set_content_bitrate(player->streamer,
1710 player->total_maximum_bitrate, player->total_bitrate);
1712 if (player->pending_seek.is_pending) {
1713 LOGW("trying to do pending seek");
1714 MMPLAYER_CMD_LOCK(player);
1715 __mmplayer_gst_pending_seek(player);
1716 MMPLAYER_CMD_UNLOCK(player);
1722 case GST_STATE_PLAYING:
1724 if (MMPLAYER_IS_STREAMING(player)) {
1725 // managed prepare async case when buffering is completed
1726 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1727 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1728 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1729 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1731 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1733 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1734 if (player->streamer->buffering_percent < 100) {
1736 MMMessageParamType msg_param = {0, };
1737 LOGW("Posting Buffering Completed Message to Application !!!");
1739 msg_param.connection.buffering = 100;
1740 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1745 if (player->gapless.stream_changed) {
1746 __mmplayer_update_content_attrs(player, ATTR_ALL);
1747 player->gapless.stream_changed = FALSE;
1750 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1751 player->seek_state = MMPLAYER_SEEK_NONE;
1752 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1756 case GST_STATE_VOID_PENDING:
1757 case GST_STATE_NULL:
1758 case GST_STATE_READY:
1768 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1770 const gchar *structure_name;
1771 gint count = 0, idx = 0;
1772 MMHandleType attrs = 0;
1775 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1777 attrs = MMPLAYER_GET_ATTRS(player);
1779 LOGE("Failed to get content attribute");
1783 if (gst_message_get_structure(msg) == NULL)
1786 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1787 if (!structure_name)
1790 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1792 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1793 const GValue *var_info = NULL;
1795 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1796 if (var_info != NULL) {
1797 if (player->adaptive_info.var_list)
1798 g_list_free_full(player->adaptive_info.var_list, g_free);
1800 /* share addr or copy the list */
1801 player->adaptive_info.var_list =
1802 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1804 count = g_list_length(player->adaptive_info.var_list);
1806 VariantData *temp = NULL;
1808 /* print out for debug */
1809 LOGD("num of variant_info %d", count);
1810 for (idx = 0; idx < count; idx++) {
1811 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1813 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1819 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1820 gint num_buffers = 0;
1821 gint extra_num_buffers = 0;
1823 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1824 player->video_num_buffers = num_buffers;
1825 LOGD("video_num_buffers : %d", player->video_num_buffers);
1828 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1829 player->video_extra_num_buffers = extra_num_buffers;
1830 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1835 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1836 __mmplayer_track_update_text_attr_info(player, msg);
1838 /* custom message */
1839 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1840 MMMessageParamType msg_param = {0,};
1841 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1842 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1845 /* custom message for RTSP attribute :
1846 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1847 sdp which has contents info is received when rtsp connection is opened.
1848 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1849 if (!strcmp(structure_name, "rtspsrc_properties")) {
1851 gchar *audio_codec = NULL;
1852 gchar *video_codec = NULL;
1853 gchar *video_frame_size = NULL;
1855 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1856 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1857 player->streaming_type = __mmplayer_get_stream_service_type(player);
1859 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1860 LOGD("rtsp_audio_codec : %s", audio_codec);
1862 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1864 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1865 LOGD("rtsp_video_codec : %s", video_codec);
1867 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1869 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1870 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1871 if (video_frame_size) {
1873 char *seperator = strchr(video_frame_size, '-');
1876 char video_width[10] = {0,};
1877 int frame_size_len = strlen(video_frame_size);
1878 int separtor_len = strlen(seperator);
1880 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1881 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1884 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1888 if (mm_attrs_commit_all(attrs))
1889 LOGE("failed to commit.");
1897 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1899 MMPlayerGstElement *mainbin;
1902 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1904 mainbin = player->pipeline->mainbin;
1906 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1908 /* we only handle messages from pipeline */
1909 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1912 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1913 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1914 player->seek_state = MMPLAYER_SEEK_NONE;
1915 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1916 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1917 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1918 LOGD("sync %s state(%s) with parent state(%s)",
1919 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1920 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1921 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1923 /* In case of streaming, pause is required before finishing seeking by buffering.
1924 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1925 Because the buffering state is controlled according to the state transition for force resume,
1926 the decodebin state should be paused as player state. */
1927 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1930 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1931 (player->streamer) &&
1932 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1933 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1934 GstQuery *query = NULL;
1935 gboolean busy = FALSE;
1938 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1939 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1940 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1941 gst_query_parse_buffering_percent(query, &busy, &percent);
1942 gst_query_unref(query);
1944 LOGD("buffered percent(%s): %d\n",
1945 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1949 __mmplayer_handle_buffering_playback(player);
1952 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1961 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1963 mm_player_t* player = (mm_player_t*)(data);
1965 MMPLAYER_RETURN_IF_FAIL(player);
1966 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1968 switch (GST_MESSAGE_TYPE(msg)) {
1969 case GST_MESSAGE_UNKNOWN:
1970 LOGD("unknown message received\n");
1973 case GST_MESSAGE_EOS:
1974 LOGD("GST_MESSAGE_EOS received");
1975 __mmplayer_gst_handle_eos_message(player, msg);
1978 case GST_MESSAGE_ERROR:
1979 __mmplayer_gst_handle_error_message(player, msg);
1982 case GST_MESSAGE_WARNING:
1985 GError* error = NULL;
1987 gst_message_parse_warning(msg, &error, &debug);
1989 LOGD("warning : %s\n", error->message);
1990 LOGD("debug : %s\n", debug);
1992 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1994 MMPLAYER_FREEIF(debug);
1995 g_error_free(error);
1999 case GST_MESSAGE_TAG:
2001 LOGD("GST_MESSAGE_TAG\n");
2002 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2003 LOGW("failed to extract tags from gstmessage\n");
2007 case GST_MESSAGE_BUFFERING:
2008 __mmplayer_gst_handle_buffering_message(player, msg);
2011 case GST_MESSAGE_STATE_CHANGED:
2012 __mmplayer_gst_handle_state_message(player, msg);
2015 case GST_MESSAGE_CLOCK_LOST:
2017 GstClock *clock = NULL;
2018 gboolean need_new_clock = FALSE;
2020 gst_message_parse_clock_lost(msg, &clock);
2021 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2023 if (!player->videodec_linked)
2024 need_new_clock = TRUE;
2025 else if (!player->ini.use_system_clock)
2026 need_new_clock = TRUE;
2028 if (need_new_clock) {
2029 LOGD("Provide clock is TRUE, do pause->resume\n");
2030 __mmplayer_gst_pause(player, FALSE);
2031 __mmplayer_gst_resume(player, FALSE);
2036 case GST_MESSAGE_NEW_CLOCK:
2038 GstClock *clock = NULL;
2039 gst_message_parse_new_clock(msg, &clock);
2040 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2044 case GST_MESSAGE_ELEMENT:
2045 __mmplayer_gst_handle_element_message(player, msg);
2048 case GST_MESSAGE_DURATION_CHANGED:
2050 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2051 if (!__mmplayer_gst_handle_duration(player, msg))
2052 LOGW("failed to update duration");
2056 case GST_MESSAGE_ASYNC_START:
2057 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2060 case GST_MESSAGE_ASYNC_DONE:
2061 __mmplayer_gst_handle_async_done_message(player, msg);
2064 #if 0 /* delete unnecessary logs */
2065 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2066 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2067 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2068 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2069 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2070 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2071 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2072 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2073 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2074 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2075 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2076 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2077 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2078 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2079 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2086 /* should not call 'gst_message_unref(msg)' */
2090 static GstBusSyncReply
2091 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2093 mm_player_t *player = (mm_player_t *)data;
2094 GstBusSyncReply reply = GST_BUS_DROP;
2096 if (!(player->pipeline && player->pipeline->mainbin)) {
2097 LOGE("player pipeline handle is null");
2098 return GST_BUS_PASS;
2101 if (!__mmplayer_gst_check_useful_message(player, message)) {
2102 gst_message_unref(message);
2103 return GST_BUS_DROP;
2106 switch (GST_MESSAGE_TYPE(message)) {
2107 case GST_MESSAGE_TAG:
2108 __mmplayer_gst_extract_tag_from_msg(player, message);
2112 GstTagList *tags = NULL;
2114 gst_message_parse_tag(message, &tags);
2116 LOGE("TAGS received from element \"%s\".\n",
2117 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2119 gst_tag_list_foreach(tags, print_tag, NULL);
2120 gst_tag_list_unref(tags);
2128 case GST_MESSAGE_DURATION_CHANGED:
2129 __mmplayer_gst_handle_duration(player, message);
2131 case GST_MESSAGE_ASYNC_DONE:
2132 /* NOTE:Don't call gst_callback directly
2133 * because previous frame can be showed even though this message is received for seek.
2136 reply = GST_BUS_PASS;
2140 if (reply == GST_BUS_DROP)
2141 gst_message_unref(message);
2147 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2149 GstElement *appsrc = element;
2150 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2151 GstBuffer *buffer = NULL;
2152 GstFlowReturn ret = GST_FLOW_OK;
2155 MMPLAYER_RETURN_IF_FAIL(element);
2156 MMPLAYER_RETURN_IF_FAIL(buf);
2158 buffer = gst_buffer_new();
2160 if (buf->offset < 0 || buf->len < 0) {
2161 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2165 if (buf->offset >= buf->len) {
2166 LOGD("call eos appsrc");
2167 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2171 if (buf->len - buf->offset < size)
2172 len = buf->len - buf->offset;
2174 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2175 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2176 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2178 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2179 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2185 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2187 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2189 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2191 buf->offset = (int)size;
2197 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2199 mm_player_t *player = (mm_player_t*)user_data;
2200 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2201 guint64 current_level_bytes = 0;
2203 MMPLAYER_RETURN_IF_FAIL(player);
2205 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2206 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2207 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2208 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2209 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2210 type = MM_PLAYER_STREAM_TYPE_TEXT;
2212 LOGE("can not enter here");
2216 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2218 LOGI("type: %d, level: %llu", type, current_level_bytes);
2220 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2221 if (player->media_stream_buffer_status_cb[type])
2222 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2223 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2227 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2229 mm_player_t *player = (mm_player_t*)user_data;
2230 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2231 guint64 current_level_bytes = 0;
2233 MMPLAYER_RETURN_IF_FAIL(player);
2235 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2236 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2237 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2238 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2239 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2240 type = MM_PLAYER_STREAM_TYPE_TEXT;
2242 LOGE("can not enter here");
2246 LOGI("type: %d, buffer is full", type);
2248 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2250 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2252 if (player->media_stream_buffer_status_cb[type])
2253 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2255 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2259 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2261 mm_player_t *player = (mm_player_t*)user_data;
2262 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2264 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2266 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2267 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2268 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2269 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2270 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2271 type = MM_PLAYER_STREAM_TYPE_TEXT;
2273 LOGE("can not enter here");
2277 LOGD("type: %d, pos: %llu", type, position);
2278 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2280 if (player->media_stream_seek_data_cb[type])
2281 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2282 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2288 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2290 #define MAX_LEN_NAME 20
2292 gboolean ret = FALSE;
2293 GstPad *sinkpad = NULL;
2294 gchar *prefix = NULL;
2295 gchar dec_name[MAX_LEN_NAME] = {0};
2296 enum MainElementID elem_id = MMPLAYER_M_NUM;
2298 MMPlayerGstElement *mainbin = NULL;
2299 GstElement *decodebin = NULL;
2300 GstCaps *dec_caps = NULL;
2304 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2306 player->pipeline->mainbin, FALSE);
2307 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2309 mainbin = player->pipeline->mainbin;
2311 case MM_PLAYER_STREAM_TYPE_AUDIO:
2313 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2315 case MM_PLAYER_STREAM_TYPE_VIDEO:
2317 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2320 LOGE("invalid type %d", type);
2324 if (mainbin[elem_id].gst) {
2325 LOGE("elem(%d) is already created", elem_id);
2329 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2331 /* create decodebin */
2332 decodebin = gst_element_factory_make("decodebin", dec_name);
2334 LOGE("failed to create %s", dec_name);
2338 mainbin[elem_id].id = elem_id;
2339 mainbin[elem_id].gst = decodebin;
2341 /* raw pad handling signal */
2342 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2343 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2345 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2346 before looking for any elements that can handle that stream.*/
2347 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2348 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2350 /* This signal is emitted when a element is added to the bin.*/
2351 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2352 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2354 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2355 LOGE("failed to add new decodebin");
2359 dec_caps = gst_pad_query_caps(srcpad, NULL);
2361 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2362 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2363 gst_caps_unref(dec_caps);
2366 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2368 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2369 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2372 gst_object_unref(GST_OBJECT(sinkpad));
2374 gst_element_sync_state_with_parent(decodebin);
2380 gst_object_unref(GST_OBJECT(sinkpad));
2382 if (mainbin[elem_id].gst) {
2383 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2384 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2385 gst_object_unref(mainbin[elem_id].gst);
2386 mainbin[elem_id].gst = NULL;
2394 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2396 #define MAX_LEN_NAME 20
2397 MMPlayerGstElement *mainbin = NULL;
2398 gchar *prefix = NULL;
2399 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2401 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2402 GstElement *src = NULL, *queue = NULL;
2403 GstPad *srcpad = NULL;
2406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2407 player->pipeline->mainbin, FALSE);
2409 mainbin = player->pipeline->mainbin;
2411 LOGD("type(%d) path is creating", type);
2413 case MM_PLAYER_STREAM_TYPE_AUDIO:
2415 if (mainbin[MMPLAYER_M_SRC].gst)
2416 src_id = MMPLAYER_M_2ND_SRC;
2418 src_id = MMPLAYER_M_SRC;
2419 queue_id = MMPLAYER_M_A_BUFFER;
2421 case MM_PLAYER_STREAM_TYPE_VIDEO:
2423 src_id = MMPLAYER_M_SRC;
2424 queue_id = MMPLAYER_M_V_BUFFER;
2426 case MM_PLAYER_STREAM_TYPE_TEXT:
2427 prefix = "subtitle";
2428 src_id = MMPLAYER_M_SUBSRC;
2429 queue_id = MMPLAYER_M_S_BUFFER;
2432 LOGE("invalid type %d", type);
2436 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2437 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2440 src = gst_element_factory_make("appsrc", src_name);
2442 LOGF("failed to create %s", src_name);
2446 mainbin[src_id].id = src_id;
2447 mainbin[src_id].gst = src;
2449 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2450 "caps", caps, NULL);
2452 /* size of many video frames are larger than default blocksize as 4096 */
2453 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2454 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2456 if (player->media_stream_buffer_max_size[type] > 0)
2457 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2459 if (player->media_stream_buffer_min_percent[type] > 0)
2460 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2462 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2463 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2465 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2466 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2467 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2468 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2469 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2470 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2473 queue = gst_element_factory_make("queue2", queue_name);
2475 LOGE("failed to create %s", queue_name);
2478 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2480 mainbin[queue_id].id = queue_id;
2481 mainbin[queue_id].gst = queue;
2483 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2484 LOGE("failed to add src");
2488 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2489 LOGE("failed to add queue");
2493 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2494 LOGE("failed to link src and queue");
2498 /* create decoder */
2499 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2501 LOGE("failed to get srcpad of queue");
2505 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2506 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2508 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2509 LOGE("failed to create decoder");
2510 gst_object_unref(GST_OBJECT(srcpad));
2514 gst_object_unref(GST_OBJECT(srcpad));
2518 if (mainbin[src_id].gst) {
2519 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2520 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2521 gst_object_unref(mainbin[src_id].gst);
2522 mainbin[src_id].gst = NULL;
2525 if (mainbin[queue_id].gst) {
2526 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2527 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2528 gst_object_unref(mainbin[queue_id].gst);
2529 mainbin[queue_id].gst = NULL;
2536 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2538 GstPad *sinkpad = NULL;
2539 GstCaps *caps = NULL;
2540 GstElement *new_element = NULL;
2541 GstStructure *str = NULL;
2542 const gchar *name = NULL;
2544 mm_player_t *player = (mm_player_t*) data;
2548 MMPLAYER_RETURN_IF_FAIL(element && pad);
2549 MMPLAYER_RETURN_IF_FAIL(player &&
2551 player->pipeline->mainbin);
2553 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2554 * num_dynamic_pad will decreased after creating a sinkbin.
2556 player->num_dynamic_pad++;
2557 LOGD("stream count inc : %d", player->num_dynamic_pad);
2559 caps = gst_pad_query_caps(pad, NULL);
2560 MMPLAYER_CHECK_NULL(caps);
2562 str = gst_caps_get_structure (caps, 0);
2563 name = gst_structure_get_string(str, "media");
2565 LOGE("cannot get mimetype from structure.\n");
2569 if (strstr(name, "video")) {
2571 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2573 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2574 if (player->v_stream_caps) {
2575 gst_caps_unref(player->v_stream_caps);
2576 player->v_stream_caps = NULL;
2579 new_element = gst_element_factory_make("fakesink", NULL);
2580 player->num_dynamic_pad--;
2585 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2586 LOGE("failed to autoplug for caps");
2590 gst_caps_unref(caps);
2595 /* excute new_element if created*/
2597 LOGD("adding new element to pipeline\n");
2599 /* set state to READY before add to bin */
2600 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2602 /* add new element to the pipeline */
2603 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2604 LOGE("failed to add autoplug element to bin\n");
2608 /* get pad from element */
2609 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2611 LOGE("failed to get sinkpad from autoplug element\n");
2616 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2617 LOGE("failed to link autoplug element\n");
2621 gst_object_unref(sinkpad);
2624 /* run. setting PLAYING here since streamming source is live source */
2625 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2629 gst_caps_unref(caps);
2635 STATE_CHANGE_FAILED:
2637 /* FIXIT : take care if new_element has already added to pipeline */
2639 gst_object_unref(GST_OBJECT(new_element));
2642 gst_object_unref(GST_OBJECT(sinkpad));
2645 gst_caps_unref(caps);
2647 /* FIXIT : how to inform this error to MSL ????? */
2648 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2649 * then post an error to application
2654 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2656 mm_player_t* player = (mm_player_t*) data;
2660 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2661 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2662 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2663 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2665 * [1] audio and video will be dumped with filesink.
2666 * [2] autoplugging is done by just using pad caps.
2667 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2668 * and the video will be dumped via filesink.
2670 if (player->num_dynamic_pad == 0) {
2671 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2673 if (!__mmplayer_gst_remove_fakesink(player,
2674 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2675 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2676 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2677 * source element are not same. To overcome this situation, this function will called
2678 * several places and several times. Therefore, this is not an error case.
2683 /* create dot before error-return. for debugging */
2684 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2686 player->no_more_pad = TRUE;
2692 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2694 GstElement* element = NULL;
2695 gchar *user_agent = NULL;
2696 MMHandleType attrs = 0;
2699 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2701 /* get profile attribute */
2702 attrs = MMPLAYER_GET_ATTRS(player);
2704 LOGE("failed to get content attribute");
2708 element = gst_element_factory_make("rtspsrc", "rtsp source");
2710 LOGE("failed to create rtspsrc element");
2715 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2717 SECURE_LOGD("user_agent : %s", user_agent);
2719 /* setting property to streaming source */
2720 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2722 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2724 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2725 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2726 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2727 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2734 __mmplayer_gst_make_http_src(mm_player_t* player)
2736 GstElement* element = NULL;
2737 MMHandleType attrs = 0;
2738 gchar *user_agent, *cookies, **cookie_list;
2739 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2740 user_agent = cookies = NULL;
2744 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2746 /* get profile attribute */
2747 attrs = MMPLAYER_GET_ATTRS(player);
2749 LOGE("failed to get content attribute");
2753 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2755 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2757 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2762 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2763 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2765 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2766 http_timeout = player->ini.http_timeout;
2769 SECURE_LOGD("location : %s", player->profile.uri);
2770 SECURE_LOGD("cookies : %s", cookies);
2771 SECURE_LOGD("user_agent : %s", user_agent);
2772 LOGD("timeout : %d", http_timeout);
2774 /* setting property to streaming source */
2775 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2776 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2778 /* parsing cookies */
2779 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2780 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2781 g_strfreev(cookie_list);
2785 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2787 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2788 LOGW("[DASH] this is still experimental feature");
2795 __mmplayer_gst_make_file_src(mm_player_t* player)
2797 GstElement* element = NULL;
2800 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2802 LOGD("using filesrc for 'file://' handler");
2803 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2804 LOGE("failed to get storage info");
2808 element = gst_element_factory_make("filesrc", "source");
2810 LOGE("failed to create filesrc");
2814 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2820 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2822 mm_player_t *player = (mm_player_t *) data;
2824 g_return_val_if_fail(player, FALSE);
2825 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2827 gst_message_ref(msg);
2829 g_mutex_lock(&player->bus_msg_q_lock);
2830 g_queue_push_tail(player->bus_msg_q, msg);
2831 g_mutex_unlock(&player->bus_msg_q_lock);
2833 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2834 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2835 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2839 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2841 mm_player_t *player = (mm_player_t*)(data);
2842 GstMessage *msg = NULL;
2846 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2848 player->pipeline->mainbin &&
2849 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2852 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2854 LOGE("cannot get BUS from the pipeline");
2858 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2860 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2861 while (!player->bus_msg_thread_exit) {
2862 g_mutex_lock(&player->bus_msg_q_lock);
2863 msg = g_queue_pop_head(player->bus_msg_q);
2864 g_mutex_unlock(&player->bus_msg_q_lock);
2866 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2869 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2870 /* handle the gst msg */
2871 __mmplayer_gst_bus_msg_callback(msg, player);
2872 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2873 gst_message_unref(msg);
2876 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2877 gst_object_unref(GST_OBJECT(bus));
2884 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2886 gint64 dur_nsec = 0;
2889 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2891 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2892 return MM_ERROR_NONE;
2894 /* NOTE : duration cannot be zero except live streaming.
2895 * Since some element could have some timing problemn with quering duration, try again.
2897 if (player->duration == 0) {
2898 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2899 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2900 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2901 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2902 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2903 player->pending_seek.is_pending = TRUE;
2904 player->pending_seek.pos = position;
2905 player->seek_state = MMPLAYER_SEEK_NONE;
2906 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2907 return MM_ERROR_PLAYER_NO_OP;
2909 player->seek_state = MMPLAYER_SEEK_NONE;
2910 return MM_ERROR_PLAYER_SEEK;
2913 player->duration = dur_nsec;
2916 if (player->duration > 0 && player->duration < position) {
2917 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2918 return MM_ERROR_INVALID_ARGUMENT;
2922 return MM_ERROR_NONE;
2926 __mmplayer_gst_check_seekable(mm_player_t* player)
2928 GstQuery *query = NULL;
2929 gboolean seekable = FALSE;
2931 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2935 query = gst_query_new_seeking(GST_FORMAT_TIME);
2936 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2937 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2938 gst_query_unref(query);
2941 LOGW("non-seekable content");
2942 player->seek_state = MMPLAYER_SEEK_NONE;
2946 LOGW("failed to get seeking query");
2947 gst_query_unref(query); /* keep seeking operation */
2958 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2960 GstState element_state = GST_STATE_VOID_PENDING;
2961 GstState element_pending_state = GST_STATE_VOID_PENDING;
2962 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2967 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2969 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2972 ret = gst_element_set_state(element, state);
2974 if (ret == GST_STATE_CHANGE_FAILURE) {
2975 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2977 /* dump state of all element */
2978 __mmplayer_dump_pipeline_state(player);
2980 return MM_ERROR_PLAYER_INTERNAL;
2983 /* return here so state transition to be done in async mode */
2985 LOGD("async state transition. not waiting for state complete.\n");
2986 return MM_ERROR_NONE;
2989 /* wait for state transition */
2990 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2992 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2993 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
2994 GST_ELEMENT_NAME(element),
2995 gst_element_state_get_name(state), timeout);
2997 LOGE(" [%s] state : %s pending : %s \n",
2998 GST_ELEMENT_NAME(element),
2999 gst_element_state_get_name(element_state),
3000 gst_element_state_get_name(element_pending_state));
3002 /* dump state of all element */
3003 __mmplayer_dump_pipeline_state(player);
3005 return MM_ERROR_PLAYER_INTERNAL;
3008 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3012 return MM_ERROR_NONE;
3015 int __mmplayer_gst_start(mm_player_t* player)
3017 int ret = MM_ERROR_NONE;
3018 gboolean async = FALSE;
3022 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3024 /* NOTE : if SetPosition was called before Start. do it now */
3025 /* streaming doesn't support it. so it should be always sync */
3026 /* !!create one more api to check if there is pending seek rather than checking variables */
3027 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3028 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3029 ret = __mmplayer_gst_pause(player, FALSE);
3030 if (ret != MM_ERROR_NONE) {
3031 LOGE("failed to set state to PAUSED for pending seek");
3035 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3036 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3037 LOGW("failed to seek pending postion. starting from the begin of content");
3040 LOGD("current state before doing transition");
3041 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3042 MMPLAYER_PRINT_STATE(player);
3044 /* set pipeline state to PLAYING */
3045 ret = __mmplayer_gst_set_state(player,
3046 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3048 if (ret == MM_ERROR_NONE) {
3049 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3051 LOGE("failed to set state to PLAYING");
3055 /* generating debug info before returning error */
3056 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3063 int __mmplayer_gst_stop(mm_player_t* player)
3065 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3066 MMHandleType attrs = 0;
3067 gboolean rewind = FALSE;
3069 int ret = MM_ERROR_NONE;
3073 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3076 LOGD("current state before doing transition");
3077 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3078 MMPLAYER_PRINT_STATE(player);
3080 attrs = MMPLAYER_GET_ATTRS(player);
3082 LOGE("cannot get content attribute\n");
3083 return MM_ERROR_PLAYER_INTERNAL;
3086 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3087 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3089 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3090 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3093 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3094 /* disable the async state transition because there could be no data in the pipeline */
3095 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3099 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3101 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3102 /* enable the async state transition as default operation */
3103 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3106 /* return if set_state has failed */
3107 if (ret != MM_ERROR_NONE) {
3108 LOGE("failed to set state.\n");
3114 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3115 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3116 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3117 LOGW("failed to rewind\n");
3118 ret = MM_ERROR_PLAYER_SEEK;
3123 player->sent_bos = FALSE;
3125 if (player->es_player_push_mode) //for cloudgame
3128 /* wait for seek to complete */
3129 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3130 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3131 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3133 LOGE("fail to stop player.\n");
3134 ret = MM_ERROR_PLAYER_INTERNAL;
3135 __mmplayer_dump_pipeline_state(player);
3138 /* generate dot file if enabled */
3139 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3146 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3148 int ret = MM_ERROR_NONE;
3152 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3153 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3155 LOGD("current state before doing transition");
3156 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3157 MMPLAYER_PRINT_STATE(player);
3159 /* set pipeline status to PAUSED */
3160 ret = __mmplayer_gst_set_state(player,
3161 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3163 if (FALSE == async) {
3164 if (ret != MM_ERROR_NONE) {
3165 GstMessage *msg = NULL;
3166 GTimer *timer = NULL;
3167 gdouble MAX_TIMEOUT_SEC = 3;
3169 LOGE("failed to set state to PAUSED");
3171 if (!player->bus_watcher) {
3172 LOGE("there is no bus msg thread. pipeline is shutting down.");
3176 if (player->msg_posted) {
3177 LOGE("error msg is already posted.");
3181 timer = g_timer_new();
3182 g_timer_start(timer);
3184 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3187 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3189 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3190 GError *error = NULL;
3192 /* parse error code */
3193 gst_message_parse_error(msg, &error, NULL);
3195 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3196 /* Note : the streaming error from the streaming source is handled
3197 * using __mmplayer_handle_streaming_error.
3199 __mmplayer_handle_streaming_error(player, msg);
3202 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3204 if (error->domain == GST_STREAM_ERROR)
3205 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3206 else if (error->domain == GST_RESOURCE_ERROR)
3207 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3208 else if (error->domain == GST_LIBRARY_ERROR)
3209 ret = __mmplayer_gst_handle_library_error(player, error->code);
3210 else if (error->domain == GST_CORE_ERROR)
3211 ret = __mmplayer_gst_handle_core_error(player, error->code);
3213 g_error_free(error);
3215 player->msg_posted = TRUE;
3217 gst_message_unref(msg);
3219 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3221 gst_object_unref(bus);
3222 g_timer_stop(timer);
3223 g_timer_destroy(timer);
3227 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3228 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3230 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3233 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3237 /* generate dot file before returning error */
3238 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3245 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3247 int ret = MM_ERROR_NONE;
3252 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3253 MM_ERROR_PLAYER_NOT_INITIALIZED);
3255 LOGD("current state before doing transition");
3256 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3257 MMPLAYER_PRINT_STATE(player);
3260 LOGD("do async state transition to PLAYING");
3262 /* set pipeline state to PLAYING */
3263 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3265 ret = __mmplayer_gst_set_state(player,
3266 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3267 if (ret != MM_ERROR_NONE) {
3268 LOGE("failed to set state to PLAYING");
3272 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3276 /* generate dot file */
3277 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3284 /* sending event to one of sinkelements */
3286 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3288 GstEvent * event2 = NULL;
3289 GList *sinks = NULL;
3290 gboolean res = FALSE;
3293 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3294 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3296 /* While adding subtitles in live feeds seek is getting called.
3297 Adding defensive check in framework layer.*/
3298 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3299 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3300 LOGE("Should not send seek event during live playback");
3305 if (player->play_subtitle)
3306 event2 = gst_event_copy((const GstEvent *)event);
3308 sinks = player->sink_elements;
3310 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3312 if (GST_IS_ELEMENT(sink)) {
3313 /* keep ref to the event */
3314 gst_event_ref(event);
3316 if ((res = gst_element_send_event(sink, event))) {
3317 LOGD("sending event[%s] to sink element [%s] success!\n",
3318 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3320 /* rtsp case, asyn_done is not called after seek during pause state */
3321 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3322 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3323 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3324 LOGD("RTSP seek completed, after pause state..\n");
3325 player->seek_state = MMPLAYER_SEEK_NONE;
3326 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3332 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3333 sinks = g_list_next(sinks);
3340 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3341 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3344 sinks = g_list_next(sinks);
3347 /* Note : Textbin is not linked to the video or audio bin.
3348 * It needs to send the event to the text sink seperatelly.
3350 if (player->play_subtitle && player->pipeline) {
3351 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3353 if (GST_IS_ELEMENT(text_sink)) {
3354 /* keep ref to the event */
3355 gst_event_ref(event2);
3357 if ((res = gst_element_send_event(text_sink, event2)))
3358 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3359 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3361 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3362 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3364 gst_event_unref(event2);
3368 gst_event_unref(event);
3376 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3377 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3378 gint64 cur, GstSeekType stop_type, gint64 stop)
3380 GstEvent* event = NULL;
3381 gboolean result = FALSE;
3385 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3387 if (player->pipeline && player->pipeline->textbin)
3388 __mmplayer_drop_subtitle(player, FALSE);
3390 event = gst_event_new_seek(rate, format, flags, cur_type,
3391 cur, stop_type, stop);
3393 result = __mmplayer_gst_send_event_to_sink(player, event);
3401 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3403 int ret = MM_ERROR_NONE;
3404 gint64 pos_nsec = 0;
3405 gboolean accurated = FALSE;
3406 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3409 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3410 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3412 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3413 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3416 ret = __mmplayer_gst_check_duration(player, position);
3417 if (ret != MM_ERROR_NONE) {
3418 LOGE("failed to check duration 0x%X", ret);
3419 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3422 if (!__mmplayer_gst_check_seekable(player))
3423 return MM_ERROR_PLAYER_NO_OP;
3425 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3426 position, player->playback_rate, player->duration);
3428 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3429 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3430 This causes problem is position calculation during normal pause resume scenarios also.
3431 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3432 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3433 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3434 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3435 LOGW("getting current position failed in seek");
3437 player->last_position = pos_nsec;
3438 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3441 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3442 LOGD("not completed seek");
3443 return MM_ERROR_PLAYER_DOING_SEEK;
3446 if (!internal_called)
3447 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3449 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3450 that's why set position through property. */
3451 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3452 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3453 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3454 (!player->videodec_linked) && (!player->audiodec_linked)) {
3456 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3457 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3459 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3460 player->seek_state = MMPLAYER_SEEK_NONE;
3461 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3463 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3465 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3467 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3469 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3470 GST_FORMAT_TIME, seek_flags,
3471 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3472 LOGE("failed to set position");
3477 /* NOTE : store last seeking point to overcome some bad operation
3478 * (returning zero when getting current position) of some elements
3480 player->last_position = position;
3482 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3483 if (player->playback_rate > 1.0)
3484 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3486 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3487 LOGD("buffering should be reset after seeking");
3488 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3489 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3493 return MM_ERROR_NONE;
3496 player->pending_seek.is_pending = TRUE;
3497 player->pending_seek.pos = position;
3499 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3500 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3501 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3502 player->pending_seek.pos);
3504 return MM_ERROR_NONE;
3507 player->seek_state = MMPLAYER_SEEK_NONE;
3508 return MM_ERROR_PLAYER_SEEK;
3512 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3514 #define TRICKPLAY_OFFSET GST_MSECOND
3516 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3517 gint64 pos_nsec = 0;
3518 gboolean ret = TRUE;
3520 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3521 MM_ERROR_PLAYER_NOT_INITIALIZED);
3523 current_state = MMPLAYER_CURRENT_STATE(player);
3525 /* NOTE : query position except paused state to overcome some bad operation
3526 * please refer to below comments in details
3528 if (current_state != MM_PLAYER_STATE_PAUSED)
3529 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3531 /* NOTE : get last point to overcome some bad operation of some elements
3532 *(returning zero when getting current position in paused state
3533 * and when failed to get postion during seeking
3535 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3536 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3538 if (player->playback_rate < 0.0)
3539 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3541 pos_nsec = player->last_position;
3544 pos_nsec = player->last_position;
3546 player->last_position = pos_nsec;
3548 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3551 if (player->duration > 0 && pos_nsec > player->duration)
3552 pos_nsec = player->duration;
3554 player->last_position = pos_nsec;
3557 *position = pos_nsec;
3559 return MM_ERROR_NONE;
3562 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3564 #define STREAMING_IS_FINISHED 0
3565 #define BUFFERING_MAX_PER 100
3566 #define DEFAULT_PER_VALUE -1
3567 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3569 MMPlayerGstElement *mainbin = NULL;
3570 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3571 gint64 buffered_total = 0;
3572 gint64 position = 0;
3573 gint buffered_sec = -1;
3574 GstBufferingMode mode = GST_BUFFERING_STREAM;
3575 gint64 content_size_time = player->duration;
3576 guint64 content_size_bytes = player->http_content_size;
3578 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3580 player->pipeline->mainbin,
3581 MM_ERROR_PLAYER_NOT_INITIALIZED);
3583 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3588 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3589 /* and rtsp is not ready yet. */
3590 LOGW("it's only used for http streaming case");
3591 return MM_ERROR_PLAYER_NO_OP;
3594 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3595 LOGW("Time format is not supported yet");
3596 return MM_ERROR_INVALID_ARGUMENT;
3599 if (content_size_time <= 0 || content_size_bytes <= 0) {
3600 LOGW("there is no content size");
3601 return MM_ERROR_NONE;
3604 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3605 LOGW("fail to get current position");
3606 return MM_ERROR_NONE;
3609 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3610 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3612 mainbin = player->pipeline->mainbin;
3613 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3615 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3616 GstQuery *query = NULL;
3617 gint byte_in_rate = 0, byte_out_rate = 0;
3618 gint64 estimated_total = 0;
3620 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3621 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3622 LOGW("fail to get buffering query from queue2");
3624 gst_query_unref(query);
3625 return MM_ERROR_NONE;
3628 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3629 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3631 if (mode == GST_BUFFERING_STREAM) {
3632 /* using only queue in case of push mode(ts / mp3) */
3633 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3634 GST_FORMAT_BYTES, &buffered_total)) {
3635 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3636 stop_per = 100 * buffered_total / content_size_bytes;
3639 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3641 guint num_of_ranges = 0;
3642 gint64 start_byte = 0, stop_byte = 0;
3644 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3645 if (estimated_total != STREAMING_IS_FINISHED) {
3646 /* buffered size info from queue2 */
3647 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3648 for (idx = 0; idx < num_of_ranges; idx++) {
3649 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3650 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3652 buffered_total += (stop_byte - start_byte);
3655 stop_per = BUFFERING_MAX_PER;
3657 gst_query_unref(query);
3660 if (stop_per == DEFAULT_PER_VALUE) {
3661 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3663 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3665 /* buffered size info from multiqueue */
3666 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3667 guint curr_size_bytes = 0;
3668 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3669 "curr-size-bytes", &curr_size_bytes, NULL);
3670 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3671 buffered_total += curr_size_bytes;
3674 if (avg_byterate > 0)
3675 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3676 else if (player->total_maximum_bitrate > 0)
3677 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3678 else if (player->total_bitrate > 0)
3679 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3681 if (buffered_sec >= 0)
3682 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3686 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3687 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3689 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3690 buffered_total, buffered_sec, *start_pos, *stop_pos);
3692 return MM_ERROR_NONE;
3695 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3697 GstElement* element = NULL;
3700 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3701 player->pipeline->mainbin, NULL);
3703 /* setup source for gapless play */
3704 switch (player->profile.uri_type) {
3706 case MM_PLAYER_URI_TYPE_FILE:
3707 element = __mmplayer_gst_make_file_src(player);
3709 case MM_PLAYER_URI_TYPE_URL_HTTP:
3710 element = __mmplayer_gst_make_http_src(player);
3713 LOGE("not support uri type %d", player->profile.uri_type);
3718 LOGE("failed to create source element");
3726 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3728 MMHandleType attrs = 0;
3731 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3732 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3734 /* get profile attribute */
3735 attrs = MMPLAYER_GET_ATTRS(player);
3737 LOGE("failed to get content attribute");
3738 return MM_ERROR_PLAYER_INTERNAL;
3741 SECURE_LOGD("uri : %s", player->profile.uri);
3743 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3744 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3745 LOGE("failed to commit");
3747 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3748 return MM_ERROR_PLAYER_INTERNAL;
3750 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3751 return MM_ERROR_PLAYER_INTERNAL;
3753 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3754 return MM_ERROR_PLAYER_INTERNAL;
3757 return MM_ERROR_NONE;
3760 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3762 MMPlayerGstElement *mainbin = NULL;
3763 GstElement *pd_src = NULL;
3764 GstElement *pd_queue = NULL;
3765 GstElement *pd_decodebin = NULL;
3766 GList* element_bucket = NULL;
3767 MMHandleType attrs = 0;
3769 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3772 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3773 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3775 /* get profile attribute */
3776 attrs = MMPLAYER_GET_ATTRS(player);
3778 LOGE("failed to get content attribute");
3779 return MM_ERROR_PLAYER_INTERNAL;
3782 LOGD("http playback with progressive download : %d", player->pd_mode);
3784 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3785 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3786 MMPLAYER_FREEIF(player->pd_file_save_path);
3788 SECURE_LOGD("PD Location : %s", path);
3790 LOGE("filed to find pd location");
3791 return MM_ERROR_PLAYER_INTERNAL;
3794 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3795 LOGE("failed to get storage info");
3796 return MM_ERROR_PLAYER_INTERNAL;
3798 player->pd_file_save_path = g_strdup(path);
3801 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3803 LOGE("failed to create PD push source");
3804 return MM_ERROR_PLAYER_INTERNAL;
3807 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3808 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3810 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3812 mainbin = player->pipeline->mainbin;
3814 /* take source element */
3815 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3816 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3817 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3820 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3821 pd_queue = gst_element_factory_make("queue2", "queue2");
3823 LOGE("failed to create pd buffer element");
3828 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3829 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3830 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3832 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3834 player->streamer->is_pd_mode = TRUE;
3836 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3837 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3838 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3840 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3841 if (!pd_decodebin) {
3842 LOGE("failed to create decodebin");
3846 /* default size of mq in decodebin is 2M
3847 * but it can cause blocking issue during seeking depends on content. */
3848 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3850 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3851 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3853 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3855 /* add elements to pipeline */
3856 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3857 LOGE("failed to add elements to pipeline");
3861 /* linking elements in the bucket by added order. */
3862 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3863 LOGE("failed to link some elements");
3867 g_list_free(element_bucket);
3870 return MM_ERROR_NONE;
3873 MMPLAYER_FREEIF(player->pd_file_save_path);
3874 g_list_free(element_bucket);
3876 if (mainbin[MMPLAYER_M_SRC].gst)
3877 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3879 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3880 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3882 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3883 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3885 mainbin[MMPLAYER_M_SRC].gst = NULL;
3886 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3887 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3889 return MM_ERROR_PLAYER_INTERNAL;
3892 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3894 MMPlayerGstElement *mainbin = NULL;
3895 GstElement* src_elem = NULL;
3896 GstElement *autoplug_elem = NULL;
3897 GList* element_bucket = NULL;
3898 MMHandleType attrs = 0;
3899 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3902 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3903 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3905 /* get profile attribute */
3906 attrs = MMPLAYER_GET_ATTRS(player);
3908 LOGE("failed to get content attribute");
3909 return MM_ERROR_PLAYER_INTERNAL;
3912 LOGD("uri type %d", player->profile.uri_type);
3914 /* create source element */
3915 switch (player->profile.uri_type) {
3916 case MM_PLAYER_URI_TYPE_URL_RTSP:
3917 src_elem = __mmplayer_gst_make_rtsp_src(player);
3919 case MM_PLAYER_URI_TYPE_URL_HTTP:
3920 src_elem = __mmplayer_gst_make_http_src(player);
3922 case MM_PLAYER_URI_TYPE_FILE:
3923 src_elem = __mmplayer_gst_make_file_src(player);
3925 case MM_PLAYER_URI_TYPE_SS:
3927 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3928 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3930 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3934 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3935 LOGD("get timeout from ini");
3936 http_timeout = player->ini.http_timeout;
3939 /* setting property to streaming source */
3940 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3943 case MM_PLAYER_URI_TYPE_MEM:
3945 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3947 src_elem = gst_element_factory_make("appsrc", "mem-source");
3949 LOGE("failed to create appsrc element");
3953 g_object_set(src_elem, "stream-type", stream_type,
3954 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3956 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3957 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3958 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3959 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3963 LOGE("not support uri type");
3968 LOGE("failed to create source element");
3969 return MM_ERROR_PLAYER_INTERNAL;
3972 mainbin = player->pipeline->mainbin;
3974 /* take source element */
3975 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3977 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3978 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3979 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3981 /* create next element for auto-plugging */
3982 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3983 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3984 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3985 if (!autoplug_elem) {
3986 LOGE("failed to create typefind element");
3990 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3991 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3992 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3993 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3994 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3995 if (!autoplug_elem) {
3996 LOGE("failed to create decodebin");
4000 /* default size of mq in decodebin is 2M
4001 * but it can cause blocking issue during seeking depends on content. */
4002 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4005 if (autoplug_elem) {
4006 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4007 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4008 mainbin[autoplug_elem_id].gst = autoplug_elem;
4010 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4013 /* add elements to pipeline */
4014 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4015 LOGE("failed to add elements to pipeline");
4019 /* linking elements in the bucket by added order. */
4020 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4021 LOGE("failed to link some elements");
4025 /* FIXME: need to check whether this is required or not. */
4026 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4027 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4028 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4029 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4031 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4032 LOGE("failed to create fakesink");
4035 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4037 /* take ownership of fakesink. we are reusing it */
4038 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4040 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4041 LOGE("failed to add fakesink to bin");
4042 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4047 g_list_free(element_bucket);
4050 return MM_ERROR_NONE;
4053 g_list_free(element_bucket);
4055 if (mainbin[MMPLAYER_M_SRC].gst)
4056 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4058 if (mainbin[autoplug_elem_id].gst)
4059 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4061 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4062 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4064 mainbin[MMPLAYER_M_SRC].gst = NULL;
4065 mainbin[autoplug_elem_id].gst = NULL;
4066 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4068 return MM_ERROR_PLAYER_INTERNAL;
4071 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4074 MMPlayerGstElement *mainbin = NULL;
4077 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4078 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4080 mainbin = player->pipeline->mainbin;
4082 /* connect bus callback */
4083 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4085 LOGE("cannot get bus from pipeline");
4086 return MM_ERROR_PLAYER_INTERNAL;
4089 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4090 player->context.thread_default = g_main_context_get_thread_default();
4091 if (player->context.thread_default == NULL) {
4092 player->context.thread_default = g_main_context_default();
4093 LOGD("thread-default context is the global default context");
4095 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4097 /* set sync handler to get tag synchronously */
4098 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4099 gst_object_unref(GST_OBJECT(bus));
4101 /* create gst bus_msb_cb thread */
4102 g_mutex_init(&player->bus_msg_thread_mutex);
4103 g_cond_init(&player->bus_msg_thread_cond);
4104 player->bus_msg_thread_exit = FALSE;
4105 player->bus_msg_thread =
4106 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4107 if (!player->bus_msg_thread) {
4108 LOGE("failed to create gst BUS msg thread");
4109 g_mutex_clear(&player->bus_msg_thread_mutex);
4110 g_cond_clear(&player->bus_msg_thread_cond);
4111 return MM_ERROR_PLAYER_INTERNAL;
4115 return MM_ERROR_NONE;