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 <mm_attrs_private.h>
31 #include <gst/app/gstappsrc.h>
33 #include "mm_player_gst.h"
34 #include "mm_player_priv.h"
35 #include "mm_player_attrs.h"
36 #include "mm_player_utils.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 ========================================================================================== */
86 /* NOTE : decide gstreamer state whether there is some playable track or not. */
88 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
90 gchar *src_element_name = NULL;
91 GstElement *src_element = NULL;
92 GstElementFactory *factory = NULL;
93 const gchar* klass = NULL;
97 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
98 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
99 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
100 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
102 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
104 src_element = GST_ELEMENT_CAST(message->src);
108 src_element_name = GST_ELEMENT_NAME(src_element);
109 if (!src_element_name)
112 factory = gst_element_get_factory(src_element);
116 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
120 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
121 error->code, error->message, src_element_name, klass);
123 /* check whether the error is posted from not-activated track or not */
124 if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
126 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
127 LOGD("current active pad index -%d", active_pad_index);
129 if (src_element_name) {
132 if (player->audio_decoders) {
133 GList *adec = player->audio_decoders;
134 for (; adec ; adec = g_list_next(adec)) {
135 gchar *name = adec->data;
137 LOGD("found audio decoder name = %s", name);
138 if (g_strrstr(name, src_element_name)) {
145 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
148 if (active_pad_index != msg_src_pos) {
149 LOGD("skip error because error is posted from no activated track");
150 return MM_ERROR_NONE;
154 switch (error->code) {
155 case GST_STREAM_ERROR_DECODE:
157 /* Demuxer can't parse one track because it's corrupted.
158 * So, the decoder for it is not linked.
159 * But, it has one playable track.
161 if (g_strrstr(klass, "Demux")) {
162 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
167 if (player->pipeline->audiobin) // PCM
168 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
170 goto CODEC_NOT_FOUND;
173 return MM_ERROR_PLAYER_INVALID_STREAM;
177 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
178 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
179 case GST_STREAM_ERROR_WRONG_TYPE:
181 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
182 LOGE("Not supported subtitle.");
183 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
185 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
188 case GST_STREAM_ERROR_FAILED:
190 /* Decoder Custom Message */
191 if (strstr(error->message, "ongoing")) {
192 if (strncasecmp(klass, "audio", 5)) {
193 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
194 LOGD("Video can keep playing.\n");
195 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
197 goto CODEC_NOT_FOUND;
199 } else if (strncasecmp(klass, "video", 5)) {
200 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
201 LOGD("Audio can keep playing.\n");
202 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
204 goto CODEC_NOT_FOUND;
207 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
211 case GST_STREAM_ERROR_DECRYPT:
212 case GST_STREAM_ERROR_DECRYPT_NOKEY:
214 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
216 if (strstr(error->message, "rights expired"))
217 return MM_ERROR_PLAYER_DRM_EXPIRED;
218 else if (strstr(error->message, "no rights"))
219 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
220 else if (strstr(error->message, "has future rights"))
221 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
222 else if (strstr(error->message, "opl violation"))
223 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
224 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
234 return MM_ERROR_PLAYER_INVALID_STREAM;
237 return MM_ERROR_PLAYER_INTERNAL;
240 LOGD("not found any available codec. Player should be destroyed.\n");
241 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
245 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
247 gint trans_err = MM_ERROR_NONE;
251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
254 case GST_CORE_ERROR_MISSING_PLUGIN:
255 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
256 case GST_CORE_ERROR_STATE_CHANGE:
257 case GST_CORE_ERROR_SEEK:
258 case GST_CORE_ERROR_NOT_IMPLEMENTED:
259 case GST_CORE_ERROR_FAILED:
260 case GST_CORE_ERROR_TOO_LAZY:
261 case GST_CORE_ERROR_PAD:
262 case GST_CORE_ERROR_THREAD:
263 case GST_CORE_ERROR_NEGOTIATION:
264 case GST_CORE_ERROR_EVENT:
265 case GST_CORE_ERROR_CAPS:
266 case GST_CORE_ERROR_TAG:
267 case GST_CORE_ERROR_CLOCK:
268 case GST_CORE_ERROR_DISABLED:
270 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
280 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
282 gint trans_err = MM_ERROR_NONE;
286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
289 case GST_LIBRARY_ERROR_FAILED:
290 case GST_LIBRARY_ERROR_TOO_LAZY:
291 case GST_LIBRARY_ERROR_INIT:
292 case GST_LIBRARY_ERROR_SHUTDOWN:
293 case GST_LIBRARY_ERROR_SETTINGS:
294 case GST_LIBRARY_ERROR_ENCODE:
296 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
306 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
308 gint trans_err = MM_ERROR_NONE;
312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
315 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
316 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
318 case GST_RESOURCE_ERROR_NOT_FOUND:
319 case GST_RESOURCE_ERROR_OPEN_READ:
320 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
321 || MMPLAYER_IS_RTSP_STREAMING(player)) {
322 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
325 case GST_RESOURCE_ERROR_READ:
326 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
327 || MMPLAYER_IS_RTSP_STREAMING(player)) {
328 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
330 } else if (message != NULL && message->src != NULL) {
331 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
332 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
334 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
335 path_type = MMPLAYER_PATH_VOD;
336 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
337 path_type = MMPLAYER_PATH_TEXT;
339 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
340 /* check storage state */
341 storage_get_state(player->storage_info[path_type].id, &storage_state);
342 player->storage_info[path_type].state = storage_state;
343 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
346 case GST_RESOURCE_ERROR_WRITE:
347 case GST_RESOURCE_ERROR_FAILED:
348 case GST_RESOURCE_ERROR_SEEK:
349 case GST_RESOURCE_ERROR_TOO_LAZY:
350 case GST_RESOURCE_ERROR_BUSY:
351 case GST_RESOURCE_ERROR_OPEN_WRITE:
352 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
353 case GST_RESOURCE_ERROR_CLOSE:
354 case GST_RESOURCE_ERROR_SYNC:
355 case GST_RESOURCE_ERROR_SETTINGS:
357 trans_err = MM_ERROR_PLAYER_INTERNAL;
367 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
369 gint trans_err = MM_ERROR_NONE;
373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
374 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
375 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
377 switch (error->code) {
378 case GST_STREAM_ERROR_FAILED:
379 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
380 case GST_STREAM_ERROR_DECODE:
381 case GST_STREAM_ERROR_WRONG_TYPE:
382 case GST_STREAM_ERROR_DECRYPT:
383 case GST_STREAM_ERROR_DECRYPT_NOKEY:
384 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
385 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
388 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
389 case GST_STREAM_ERROR_TOO_LAZY:
390 case GST_STREAM_ERROR_ENCODE:
391 case GST_STREAM_ERROR_DEMUX:
392 case GST_STREAM_ERROR_MUX:
393 case GST_STREAM_ERROR_FORMAT:
395 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
405 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
407 MMMessageParamType msg_param;
408 gchar *msg_src_element;
412 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
413 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
415 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
417 memset(&msg_param, 0, sizeof(MMMessageParamType));
419 if (error->domain == GST_CORE_ERROR) {
420 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
421 } else if (error->domain == GST_LIBRARY_ERROR) {
422 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
423 } else if (error->domain == GST_RESOURCE_ERROR) {
424 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
425 } else if (error->domain == GST_STREAM_ERROR) {
426 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
428 LOGW("This error domain is not defined.\n");
430 /* we treat system error as an internal error */
431 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
435 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
437 msg_param.data = (void *) error->message;
439 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
440 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
444 if (msg_param.code == MM_ERROR_NONE)
447 /* skip error to avoid duplicated posting */
448 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
449 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
450 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
451 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
453 /* The error will be handled by mused.
454 * @ref _mmplayer_manage_external_storage_state() */
456 LOGW("storage is removed, skip error post");
460 /* post error to application */
461 if (!player->msg_posted) {
462 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
463 /* don't post more if one was sent already */
464 player->msg_posted = TRUE;
466 LOGD("skip error post because it's sent already.\n");
474 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
477 MMMessageParamType msg_param;
478 gchar *msg_src_element = NULL;
479 GstStructure *s = NULL;
481 gchar *error_string = NULL;
485 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
486 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
488 s = gst_structure_copy(gst_message_get_structure(message));
491 if (!gst_structure_get_uint(s, "error_id", &error_id))
492 error_id = MMPLAYER_STREAMING_ERROR_NONE;
495 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
498 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
501 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
504 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
507 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
510 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
513 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
516 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
519 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
522 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
525 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
528 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
531 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
534 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
540 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
543 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
546 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
549 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
552 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
555 case MMPLAYER_STREAMING_ERROR_GONE:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
558 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
561 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
564 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
567 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
570 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
573 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
576 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
579 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
582 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
585 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
588 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
591 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
594 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
597 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
600 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
603 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
606 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
607 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
609 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
610 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
612 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
613 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
615 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
616 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
618 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
619 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
621 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
622 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
624 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
625 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
627 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
628 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
632 gst_structure_free(s);
633 return MM_ERROR_PLAYER_STREAMING_FAIL;
637 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
639 msg_param.data = (void *) error_string;
642 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
644 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
645 msg_src_element, msg_param.code, (char*)msg_param.data);
648 /* post error to application */
649 if (!player->msg_posted) {
650 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
652 /* don't post more if one was sent already */
653 player->msg_posted = TRUE;
655 LOGD("skip error post because it's sent already.\n");
657 gst_structure_free(s);
658 g_free(error_string);
666 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
668 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
669 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
670 gst_tag_list_get_string(tags, "stitching_software",
671 &metadata->stitching_software);
672 gst_tag_list_get_string(tags, "projection_type",
673 &metadata->projection_type_string);
674 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
675 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
676 gst_tag_list_get_int(tags, "init_view_heading",
677 &metadata->init_view_heading);
678 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
679 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
680 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
681 gst_tag_list_get_int(tags, "full_pano_width_pixels",
682 &metadata->full_pano_width_pixels);
683 gst_tag_list_get_int(tags, "full_pano_height_pixels",
684 &metadata->full_pano_height_pixels);
685 gst_tag_list_get_int(tags, "cropped_area_image_width",
686 &metadata->cropped_area_image_width);
687 gst_tag_list_get_int(tags, "cropped_area_image_height",
688 &metadata->cropped_area_image_height);
689 gst_tag_list_get_int(tags, "cropped_area_left",
690 &metadata->cropped_area_left);
691 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
692 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
693 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
694 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
698 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
701 /* macro for better code readability */
702 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
703 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
704 if (string != NULL) { \
705 SECURE_LOGD("update tag string : %s\n", string); \
706 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
707 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
708 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
709 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
710 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
711 g_free(new_string); \
714 mm_attrs_set_string_by_name(attribute, playertag, string); \
721 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
723 GstSample *sample = NULL;\
724 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
725 GstMapInfo info = GST_MAP_INFO_INIT;\
726 buffer = gst_sample_get_buffer(sample);\
727 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
728 LOGD("failed to get image data from tag");\
729 gst_sample_unref(sample);\
732 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
733 MMPLAYER_FREEIF(player->album_art);\
734 player->album_art = (gchar *)g_malloc(info.size);\
735 if (player->album_art) {\
736 memcpy(player->album_art, info.data, info.size);\
737 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
738 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
739 msg_param.data = (void *)player->album_art;\
740 msg_param.size = info.size;\
741 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
742 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
745 gst_buffer_unmap(buffer, &info);\
746 gst_sample_unref(sample);\
750 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
752 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
755 gchar *tag_list_str = NULL; \
756 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
757 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
758 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
759 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
760 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
762 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
763 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
764 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
765 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
766 player->bitrate[track_type] = v_uint; \
767 player->total_bitrate = 0; \
768 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
769 player->total_bitrate += player->bitrate[i]; \
770 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
771 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
772 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
773 player->maximum_bitrate[track_type] = v_uint; \
774 player->total_maximum_bitrate = 0; \
775 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
776 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
777 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
778 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
780 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
783 g_free(tag_list_str); \
788 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
789 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
791 string = g_strdup_printf("%d", g_date_get_year(date));\
792 mm_attrs_set_string_by_name(attribute, playertag, string);\
793 SECURE_LOGD("metainfo year : %s\n", string);\
794 MMPLAYER_FREEIF(string);\
799 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
800 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
801 if (datetime != NULL) {\
802 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
803 mm_attrs_set_string_by_name(attribute, playertag, string);\
804 SECURE_LOGD("metainfo year : %s\n", string);\
805 MMPLAYER_FREEIF(string);\
806 gst_date_time_unref(datetime);\
810 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
811 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
813 /* FIXIT : don't know how to store date */\
819 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
820 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
822 /* FIXIT : don't know how to store date */\
829 GstTagList* tag_list = NULL;
831 MMHandleType attrs = 0;
836 GstDateTime *datetime = NULL;
838 GstBuffer *buffer = NULL;
840 MMMessageParamType msg_param = {0, };
842 /* currently not used. but those are needed for above macro */
843 //guint64 v_uint64 = 0;
844 //gdouble v_double = 0;
846 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
848 attrs = MMPLAYER_GET_ATTRS(player);
850 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
852 /* get tag list from gst message */
853 gst_message_parse_tag(msg, &tag_list);
855 /* store tags to player attributes */
856 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
857 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
858 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
859 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
860 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
861 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
862 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
863 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
864 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
865 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
866 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
867 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
868 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
869 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
870 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
871 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
872 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
874 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
876 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
877 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
878 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
883 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
884 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
885 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
887 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
888 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
889 MMPLAYER_UPDATE_TAG_LOCK(player);
890 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
891 MMPLAYER_UPDATE_TAG_UNLOCK(player);
892 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
901 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
903 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
904 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
906 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
907 if (player->video360_metadata.is_spherical == -1) {
908 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
909 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
910 player->video360_metadata.is_spherical);
911 if (player->video360_metadata.is_spherical == 1) {
912 LOGD("This is spherical content for 360 playback.");
913 player->is_content_spherical = TRUE;
915 LOGD("This is not spherical content");
916 player->is_content_spherical = FALSE;
919 if (player->video360_metadata.projection_type_string) {
920 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
921 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
923 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
924 player->is_content_spherical = player->is_video360_enabled = FALSE;
928 if (player->video360_metadata.stereo_mode_string) {
929 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
930 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
931 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
932 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
933 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
934 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
936 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
937 player->is_content_spherical = player->is_video360_enabled = FALSE;
943 if (mmf_attrs_commit(attrs))
944 LOGE("failed to commit.\n");
946 gst_tag_list_free(tag_list);
951 /* if retval is FALSE, it will be dropped for perfomance. */
953 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
955 gboolean retval = FALSE;
957 if (!(player->pipeline && player->pipeline->mainbin)) {
958 LOGE("player pipeline handle is null");
962 switch (GST_MESSAGE_TYPE(message)) {
963 case GST_MESSAGE_TAG:
964 case GST_MESSAGE_EOS:
965 case GST_MESSAGE_ERROR:
966 case GST_MESSAGE_WARNING:
967 case GST_MESSAGE_CLOCK_LOST:
968 case GST_MESSAGE_NEW_CLOCK:
969 case GST_MESSAGE_ELEMENT:
970 case GST_MESSAGE_DURATION_CHANGED:
971 case GST_MESSAGE_ASYNC_START:
974 case GST_MESSAGE_ASYNC_DONE:
975 case GST_MESSAGE_STATE_CHANGED:
976 /* we only handle messages from pipeline */
977 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
982 case GST_MESSAGE_BUFFERING:
984 gint buffer_percent = 0;
987 gst_message_parse_buffering(message, &buffer_percent);
988 if (buffer_percent != MAX_BUFFER_PERCENT) {
989 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
993 if (!MMPLAYER_CMD_TRYLOCK(player)) {
994 LOGW("can't get cmd lock, send msg to bus");
998 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
999 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1000 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1003 MMPLAYER_CMD_UNLOCK(player);
1016 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1018 MMHandleType attrs = 0;
1019 guint64 data_size = 0;
1021 gint64 pos_nsec = 0;
1024 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1026 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1028 attrs = MMPLAYER_GET_ATTRS(player);
1030 LOGE("fail to get attributes.\n");
1034 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1035 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1037 if (stat(path, &sb) == 0)
1038 data_size = (guint64)sb.st_size;
1039 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1040 data_size = player->http_content_size;
1043 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1044 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1050 __mmplayer_handle_buffering_playback(mm_player_t* player)
1052 int ret = MM_ERROR_NONE;
1053 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1054 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1055 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1056 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1058 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1059 LOGW("do nothing for buffering msg\n");
1060 ret = MM_ERROR_PLAYER_INVALID_STATE;
1064 prev_state = MMPLAYER_PREV_STATE(player);
1065 current_state = MMPLAYER_CURRENT_STATE(player);
1066 target_state = MMPLAYER_TARGET_STATE(player);
1067 pending_state = MMPLAYER_PENDING_STATE(player);
1069 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1070 MMPLAYER_STATE_GET_NAME(prev_state),
1071 MMPLAYER_STATE_GET_NAME(current_state),
1072 MMPLAYER_STATE_GET_NAME(pending_state),
1073 MMPLAYER_STATE_GET_NAME(target_state),
1074 player->streamer->buffering_state);
1076 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1077 /* NOTE : if buffering has done, player has to go to target state. */
1078 switch (target_state) {
1079 case MM_PLAYER_STATE_PAUSED:
1081 switch (pending_state) {
1082 case MM_PLAYER_STATE_PLAYING:
1083 __mmplayer_gst_pause(player, TRUE);
1086 case MM_PLAYER_STATE_PAUSED:
1087 LOGD("player is already going to paused state, there is nothing to do.\n");
1090 case MM_PLAYER_STATE_NONE:
1091 case MM_PLAYER_STATE_NULL:
1092 case MM_PLAYER_STATE_READY:
1094 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1100 case MM_PLAYER_STATE_PLAYING:
1102 switch (pending_state) {
1103 case MM_PLAYER_STATE_NONE:
1105 if (current_state != MM_PLAYER_STATE_PLAYING)
1106 __mmplayer_gst_resume(player, TRUE);
1110 case MM_PLAYER_STATE_PAUSED:
1111 /* NOTE: It should be worked as asynchronously.
1112 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1114 if (current_state == MM_PLAYER_STATE_PLAYING) {
1115 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1116 * The current state should be changed to paused purposely to prevent state conflict.
1118 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1120 __mmplayer_gst_resume(player, TRUE);
1123 case MM_PLAYER_STATE_PLAYING:
1124 LOGD("player is already going to playing state, there is nothing to do.\n");
1127 case MM_PLAYER_STATE_NULL:
1128 case MM_PLAYER_STATE_READY:
1130 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1136 case MM_PLAYER_STATE_NULL:
1137 case MM_PLAYER_STATE_READY:
1138 case MM_PLAYER_STATE_NONE:
1140 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1144 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1145 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1147 switch (pending_state) {
1148 case MM_PLAYER_STATE_NONE:
1150 if (current_state != MM_PLAYER_STATE_PAUSED) {
1151 /* rtsp streaming pause makes rtsp server stop sending data. */
1152 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1153 LOGD("set pause state during buffering\n");
1154 __mmplayer_gst_pause(player, TRUE);
1160 case MM_PLAYER_STATE_PLAYING:
1161 /* rtsp streaming pause makes rtsp server stop sending data. */
1162 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1163 __mmplayer_gst_pause(player, TRUE);
1166 case MM_PLAYER_STATE_PAUSED:
1169 case MM_PLAYER_STATE_NULL:
1170 case MM_PLAYER_STATE_READY:
1172 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1181 static VariantData *
1182 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1184 VariantData *var_info = NULL;
1185 g_return_val_if_fail(self != NULL, NULL);
1187 var_info = g_new0(VariantData, 1);
1188 if (!var_info) return NULL;
1189 var_info->bandwidth = self->bandwidth;
1190 var_info->width = self->width;
1191 var_info->height = self->height;
1196 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1202 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1203 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1205 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1206 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1207 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1209 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1210 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1211 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1214 /* handling audio clip which has vbr. means duration is keep changing */
1215 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1224 __mmplayer_eos_timer_cb(gpointer u_data)
1226 mm_player_t* player = NULL;
1227 MMHandleType attrs = 0;
1230 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1232 player = (mm_player_t*) u_data;
1233 attrs = MMPLAYER_GET_ATTRS(player);
1235 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1239 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1240 if (ret_value != MM_ERROR_NONE)
1241 LOGE("seeking to 0 failed in repeat play");
1244 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1247 /* we are returning FALSE as we need only one posting */
1252 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1254 MMPLAYER_RETURN_IF_FAIL(player);
1256 /* post now if delay is zero */
1257 if (delay_in_ms == 0 || player->audio_stream_render_cb_ex) {
1258 LOGD("eos delay is zero. posting EOS now\n");
1259 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1261 if (player->audio_stream_render_cb_ex)
1262 __mmplayer_cancel_eos_timer(player);
1267 /* cancel if existing */
1268 __mmplayer_cancel_eos_timer(player);
1270 /* init new timeout */
1271 /* NOTE : consider give high priority to this timer */
1272 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1274 player->eos_timer = g_timeout_add(delay_in_ms,
1275 __mmplayer_eos_timer_cb, player);
1277 player->context.global_default = g_main_context_default();
1278 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1280 /* check timer is valid. if not, send EOS now */
1281 if (player->eos_timer == 0) {
1282 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1283 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1287 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1289 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1290 int ret = MM_ERROR_NONE;
1294 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1296 if (!player->pending_seek.is_pending) {
1297 LOGD("pending seek is not reserved. nothing to do.\n");
1301 /* check player state if player could pending seek or not. */
1302 current_state = MMPLAYER_CURRENT_STATE(player);
1304 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1305 LOGW("try to pending seek in %s state, try next time. \n",
1306 MMPLAYER_STATE_GET_NAME(current_state));
1310 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1312 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1314 if (MM_ERROR_NONE != ret)
1315 LOGE("failed to seek pending postion. just keep staying current position.\n");
1317 player->pending_seek.is_pending = FALSE;
1325 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1327 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1329 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1331 audiobin = player->pipeline->audiobin; /* can be null */
1332 videobin = player->pipeline->videobin; /* can be null */
1333 textbin = player->pipeline->textbin; /* can be null */
1335 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1337 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1338 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1340 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1341 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1343 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1344 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1350 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1352 MMPlayerGstElement *textbin;
1355 MMPLAYER_RETURN_IF_FAIL(player &&
1357 player->pipeline->textbin);
1359 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1361 textbin = player->pipeline->textbin;
1364 LOGD("Drop subtitle text after getting EOS\n");
1366 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1367 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1369 player->is_subtitle_force_drop = TRUE;
1371 if (player->is_subtitle_force_drop == TRUE) {
1372 LOGD("Enable subtitle data path without drop\n");
1374 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1375 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1377 LOGD("non-connected with external display");
1379 player->is_subtitle_force_drop = FALSE;
1385 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1387 MMHandleType attrs = 0;
1392 /* NOTE : EOS event is comming multiple time. watch out it */
1393 /* check state. we only process EOS when pipeline state goes to PLAYING */
1394 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1395 LOGD("EOS received on non-playing state. ignoring it");
1399 if (player->pipeline && player->pipeline->textbin)
1400 __mmplayer_drop_subtitle(player, TRUE);
1402 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1403 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1405 /* rewind if repeat count is greater then zero */
1406 /* get play count */
1407 attrs = MMPLAYER_GET_ATTRS(player);
1410 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1412 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1414 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1415 if (player->playback_rate < 0.0) {
1416 player->resumed_by_rewind = TRUE;
1417 _mmplayer_set_mute((MMHandleType)player, 0);
1418 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1421 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1424 player->sent_bos = FALSE;
1426 LOGD("do not post eos msg for repeating");
1431 if (player->pipeline)
1432 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1434 /* post eos message to application */
1435 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1437 /* reset last position */
1438 player->last_position = 0;
1445 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1447 GError *error = NULL;
1448 gchar* debug = NULL;
1452 /* generating debug info before returning error */
1453 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1455 /* get error code */
1456 gst_message_parse_error(msg, &error, &debug);
1458 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1459 /* Note : the streaming error from the streaming source is handled
1460 * using __mmplayer_handle_streaming_error.
1462 __mmplayer_handle_streaming_error(player, msg);
1464 /* dump state of all element */
1465 __mmplayer_dump_pipeline_state(player);
1467 /* traslate gst error code to msl error code. then post it
1468 * to application if needed
1470 __mmplayer_handle_gst_error(player, msg, error);
1473 LOGE("error debug : %s", debug);
1476 if (MMPLAYER_IS_HTTP_PD(player))
1477 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1479 MMPLAYER_FREEIF(debug);
1480 g_error_free(error);
1487 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1489 MMMessageParamType msg_param = {0, };
1490 int bRet = MM_ERROR_NONE;
1493 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1495 if (!MMPLAYER_IS_STREAMING(player)) {
1496 LOGW("this is not streaming playback.");
1500 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1501 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1502 /* skip the playback control by buffering msg while user request is handled. */
1505 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1507 gst_message_parse_buffering(msg, &per);
1508 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1510 msg_param.connection.buffering = per;
1511 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1515 MMPLAYER_CMD_LOCK(player);
1518 if (!player->streamer) {
1519 LOGW("Pipeline is shutting down");
1520 MMPLAYER_CMD_UNLOCK(player);
1524 /* ignore the remained buffering message till getting 100% msg */
1525 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1526 gint buffer_percent = 0;
1528 gst_message_parse_buffering(msg, &buffer_percent);
1530 if (buffer_percent == MAX_BUFFER_PERCENT) {
1531 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1532 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1534 MMPLAYER_CMD_UNLOCK(player);
1538 /* ignore the remained buffering message */
1539 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1540 gint buffer_percent = 0;
1542 gst_message_parse_buffering(msg, &buffer_percent);
1544 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1545 player->streamer->buffering_percent, buffer_percent);
1547 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1548 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1549 player->streamer->buffering_req.is_pre_buffering = FALSE;
1551 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1553 LOGD("interrupted buffering - ignored the remained buffering msg!");
1554 MMPLAYER_CMD_UNLOCK(player);
1559 __mmplayer_update_buffer_setting(player, msg);
1561 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1563 if (bRet == MM_ERROR_NONE) {
1564 msg_param.connection.buffering = player->streamer->buffering_percent;
1565 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1567 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1568 player->pending_resume &&
1569 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1571 player->is_external_subtitle_added_now = FALSE;
1572 player->pending_resume = FALSE;
1573 _mmplayer_resume((MMHandleType)player);
1576 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1577 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1579 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1580 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1581 player->seek_state = MMPLAYER_SEEK_NONE;
1582 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1583 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1584 /* Considering the async state trasition in case of RTSP.
1585 After getting state change gst msg, seek cmpleted msg will be posted. */
1586 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1590 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1591 if (!player->streamer) {
1592 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1593 MMPLAYER_CMD_UNLOCK(player);
1597 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1599 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1600 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1602 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1603 msg_param.connection.buffering = player->streamer->buffering_percent;
1604 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1606 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1609 msg_param.connection.buffering = player->streamer->buffering_percent;
1610 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1613 MMPLAYER_CMD_UNLOCK(player);
1621 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1623 MMPlayerGstElement *mainbin;
1624 const GValue *voldstate, *vnewstate, *vpending;
1625 GstState oldstate = GST_STATE_NULL;
1626 GstState newstate = GST_STATE_NULL;
1627 GstState pending = GST_STATE_NULL;
1630 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1632 mainbin = player->pipeline->mainbin;
1634 /* we only handle messages from pipeline */
1635 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1638 /* get state info from msg */
1639 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1640 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1641 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1643 if (!voldstate || !vnewstate) {
1644 LOGE("received msg has wrong format.");
1648 oldstate = (GstState)voldstate->data[0].v_int;
1649 newstate = (GstState)vnewstate->data[0].v_int;
1651 pending = (GstState)vpending->data[0].v_int;
1653 LOGD("state changed [%s] : %s ---> %s final : %s",
1654 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1655 gst_element_state_get_name((GstState)oldstate),
1656 gst_element_state_get_name((GstState)newstate),
1657 gst_element_state_get_name((GstState)pending));
1659 if (newstate == GST_STATE_PLAYING) {
1660 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1662 int retVal = MM_ERROR_NONE;
1663 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1665 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1667 if (MM_ERROR_NONE != retVal)
1668 LOGE("failed to seek pending postion. just keep staying current position.");
1670 player->pending_seek.is_pending = FALSE;
1674 if (oldstate == newstate) {
1675 LOGD("pipeline reports state transition to old state");
1680 case GST_STATE_PAUSED:
1682 gboolean prepare_async = FALSE;
1684 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1685 // managed prepare async case
1686 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1687 LOGD("checking prepare mode for async transition - %d", prepare_async);
1690 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1691 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1693 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1694 __mm_player_streaming_set_content_bitrate(player->streamer,
1695 player->total_maximum_bitrate, player->total_bitrate);
1697 if (player->pending_seek.is_pending) {
1698 LOGW("trying to do pending seek");
1699 MMPLAYER_CMD_LOCK(player);
1700 __mmplayer_gst_pending_seek(player);
1701 MMPLAYER_CMD_UNLOCK(player);
1707 case GST_STATE_PLAYING:
1709 if (MMPLAYER_IS_STREAMING(player)) {
1710 // managed prepare async case when buffering is completed
1711 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1712 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1713 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1714 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1716 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1718 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1719 if (player->streamer->buffering_percent < 100) {
1721 MMMessageParamType msg_param = {0, };
1722 LOGW("Posting Buffering Completed Message to Application !!!");
1724 msg_param.connection.buffering = 100;
1725 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1730 if (player->gapless.stream_changed) {
1731 __mmplayer_update_content_attrs(player, ATTR_ALL);
1732 player->gapless.stream_changed = FALSE;
1735 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1736 player->seek_state = MMPLAYER_SEEK_NONE;
1737 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1741 case GST_STATE_VOID_PENDING:
1742 case GST_STATE_NULL:
1743 case GST_STATE_READY:
1753 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1755 const gchar *structure_name;
1756 gint count = 0, idx = 0;
1757 MMHandleType attrs = 0;
1760 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1762 attrs = MMPLAYER_GET_ATTRS(player);
1764 LOGE("Failed to get content attribute");
1768 if (gst_message_get_structure(msg) == NULL)
1771 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1772 if (!structure_name)
1775 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1777 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1778 const GValue *var_info = NULL;
1780 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1781 if (var_info != NULL) {
1782 if (player->adaptive_info.var_list)
1783 g_list_free_full(player->adaptive_info.var_list, g_free);
1785 /* share addr or copy the list */
1786 player->adaptive_info.var_list =
1787 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1789 count = g_list_length(player->adaptive_info.var_list);
1791 VariantData *temp = NULL;
1793 /* print out for debug */
1794 LOGD("num of variant_info %d", count);
1795 for (idx = 0; idx < count; idx++) {
1796 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1798 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1804 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1805 gint num_buffers = 0;
1806 gint extra_num_buffers = 0;
1808 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1809 player->video_num_buffers = num_buffers;
1810 LOGD("video_num_buffers : %d", player->video_num_buffers);
1813 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1814 player->video_extra_num_buffers = extra_num_buffers;
1815 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1820 if (!strcmp(structure_name, "Language_list")) {
1821 const GValue *lang_list = NULL;
1822 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1823 if (lang_list != NULL) {
1824 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1826 LOGD("Total audio tracks(from parser) = %d \n", count);
1830 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1831 const GValue *lang_list = NULL;
1832 MMPlayerLangStruct *temp = NULL;
1834 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1835 if (lang_list != NULL) {
1836 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1838 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1839 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1840 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1841 if (mmf_attrs_commit(attrs))
1842 LOGE("failed to commit.\n");
1843 LOGD("Total subtitle tracks = %d \n", count);
1846 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1848 LOGD("value of lang_key is %s and lang_code is %s",
1849 temp->language_key, temp->language_code);
1852 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1853 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1858 /* custom message */
1859 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1860 MMMessageParamType msg_param = {0,};
1861 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1862 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1865 /* custom message for RTSP attribute :
1866 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1867 sdp which has contents info is received when rtsp connection is opened.
1868 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1869 if (!strcmp(structure_name, "rtspsrc_properties")) {
1871 gchar *audio_codec = NULL;
1872 gchar *video_codec = NULL;
1873 gchar *video_frame_size = NULL;
1875 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1876 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1877 player->streaming_type = __mmplayer_get_stream_service_type(player);
1879 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1880 LOGD("rtsp_audio_codec : %s", audio_codec);
1882 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1884 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1885 LOGD("rtsp_video_codec : %s", video_codec);
1887 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1889 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1890 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1891 if (video_frame_size) {
1893 char *seperator = strchr(video_frame_size, '-');
1896 char video_width[10] = {0,};
1897 int frame_size_len = strlen(video_frame_size);
1898 int separtor_len = strlen(seperator);
1900 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1901 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1904 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1908 if (mmf_attrs_commit(attrs))
1909 LOGE("failed to commit.\n");
1917 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1919 MMPlayerGstElement *mainbin;
1922 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1924 mainbin = player->pipeline->mainbin;
1926 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1928 /* we only handle messages from pipeline */
1929 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1932 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1933 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1934 player->seek_state = MMPLAYER_SEEK_NONE;
1935 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1936 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1937 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1938 LOGD("sync %s state(%s) with parent state(%s)",
1939 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1940 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1941 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1943 /* In case of streaming, pause is required before finishing seeking by buffering.
1944 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1945 Because the buffering state is controlled according to the state transition for force resume,
1946 the decodebin state should be paused as player state. */
1947 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1950 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1951 (player->streamer) &&
1952 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1953 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1954 GstQuery *query = NULL;
1955 gboolean busy = FALSE;
1958 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1959 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1960 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1961 gst_query_parse_buffering_percent(query, &busy, &percent);
1962 gst_query_unref(query);
1964 LOGD("buffered percent(%s): %d\n",
1965 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1969 __mmplayer_handle_buffering_playback(player);
1972 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1981 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1983 mm_player_t* player = (mm_player_t*)(data);
1985 MMPLAYER_RETURN_IF_FAIL(player);
1986 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1988 switch (GST_MESSAGE_TYPE(msg)) {
1989 case GST_MESSAGE_UNKNOWN:
1990 LOGD("unknown message received\n");
1993 case GST_MESSAGE_EOS:
1994 LOGD("GST_MESSAGE_EOS received");
1995 __mmplayer_gst_handle_eos_message(player, msg);
1998 case GST_MESSAGE_ERROR:
1999 __mmplayer_gst_handle_error_message(player, msg);
2002 case GST_MESSAGE_WARNING:
2005 GError* error = NULL;
2007 gst_message_parse_warning(msg, &error, &debug);
2009 LOGD("warning : %s\n", error->message);
2010 LOGD("debug : %s\n", debug);
2012 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2014 MMPLAYER_FREEIF(debug);
2015 g_error_free(error);
2019 case GST_MESSAGE_TAG:
2021 LOGD("GST_MESSAGE_TAG\n");
2022 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2023 LOGW("failed to extract tags from gstmessage\n");
2027 case GST_MESSAGE_BUFFERING:
2028 __mmplayer_gst_handle_buffering_message(player, msg);
2031 case GST_MESSAGE_STATE_CHANGED:
2032 __mmplayer_gst_handle_state_message(player, msg);
2035 case GST_MESSAGE_CLOCK_LOST:
2037 GstClock *clock = NULL;
2038 gboolean need_new_clock = FALSE;
2040 gst_message_parse_clock_lost(msg, &clock);
2041 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2043 if (!player->videodec_linked)
2044 need_new_clock = TRUE;
2045 else if (!player->ini.use_system_clock)
2046 need_new_clock = TRUE;
2048 if (need_new_clock) {
2049 LOGD("Provide clock is TRUE, do pause->resume\n");
2050 __mmplayer_gst_pause(player, FALSE);
2051 __mmplayer_gst_resume(player, FALSE);
2056 case GST_MESSAGE_NEW_CLOCK:
2058 GstClock *clock = NULL;
2059 gst_message_parse_new_clock(msg, &clock);
2060 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2064 case GST_MESSAGE_ELEMENT:
2065 __mmplayer_gst_handle_element_message(player, msg);
2068 case GST_MESSAGE_DURATION_CHANGED:
2070 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2071 if (!__mmplayer_gst_handle_duration(player, msg))
2072 LOGW("failed to update duration");
2076 case GST_MESSAGE_ASYNC_START:
2077 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2080 case GST_MESSAGE_ASYNC_DONE:
2081 __mmplayer_gst_handle_async_done_message(player, msg);
2084 #if 0 /* delete unnecessary logs */
2085 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2086 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2087 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2088 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2089 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2090 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2091 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2092 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2093 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2094 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2095 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2096 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2097 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2098 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2099 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2106 /* should not call 'gst_message_unref(msg)' */
2110 static GstBusSyncReply
2111 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2113 mm_player_t *player = (mm_player_t *)data;
2114 GstBusSyncReply reply = GST_BUS_DROP;
2116 if (!(player->pipeline && player->pipeline->mainbin)) {
2117 LOGE("player pipeline handle is null");
2118 return GST_BUS_PASS;
2121 if (!__mmplayer_gst_check_useful_message(player, message)) {
2122 gst_message_unref(message);
2123 return GST_BUS_DROP;
2126 switch (GST_MESSAGE_TYPE(message)) {
2127 case GST_MESSAGE_STATE_CHANGED:
2128 /* post directly for fast launch */
2129 if (player->sync_handler) {
2130 __mmplayer_gst_bus_msg_callback(message, player);
2131 reply = GST_BUS_DROP;
2133 reply = GST_BUS_PASS;
2135 case GST_MESSAGE_TAG:
2136 __mmplayer_gst_extract_tag_from_msg(player, message);
2140 GstTagList *tags = NULL;
2142 gst_message_parse_tag(message, &tags);
2144 LOGE("TAGS received from element \"%s\".\n",
2145 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2147 gst_tag_list_foreach(tags, print_tag, NULL);
2148 gst_tag_list_free(tags);
2156 case GST_MESSAGE_DURATION_CHANGED:
2157 __mmplayer_gst_handle_duration(player, message);
2159 case GST_MESSAGE_ASYNC_DONE:
2160 /* NOTE:Don't call gst_callback directly
2161 * because previous frame can be showed even though this message is received for seek.
2164 reply = GST_BUS_PASS;
2168 if (reply == GST_BUS_DROP)
2169 gst_message_unref(message);
2175 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2177 GstElement *appsrc = element;
2178 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2179 GstBuffer *buffer = NULL;
2180 GstFlowReturn ret = GST_FLOW_OK;
2183 MMPLAYER_RETURN_IF_FAIL(element);
2184 MMPLAYER_RETURN_IF_FAIL(buf);
2186 buffer = gst_buffer_new();
2188 if (buf->offset < 0 || buf->len < 0) {
2189 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2193 if (buf->offset >= buf->len) {
2194 LOGD("call eos appsrc");
2195 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2199 if (buf->len - buf->offset < size)
2200 len = buf->len - buf->offset;
2202 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2203 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2204 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2206 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2207 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2213 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2215 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2217 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2219 buf->offset = (int)size;
2225 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2227 mm_player_t *player = (mm_player_t*)user_data;
2228 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2229 guint64 current_level_bytes = 0;
2231 MMPLAYER_RETURN_IF_FAIL(player);
2233 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2234 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2235 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2236 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2237 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2238 type = MM_PLAYER_STREAM_TYPE_TEXT;
2240 LOGE("can not enter here");
2244 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2246 LOGI("type: %d, level: %llu", type, current_level_bytes);
2248 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2249 if (player->media_stream_buffer_status_cb[type])
2250 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2251 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2255 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2257 mm_player_t *player = (mm_player_t*)user_data;
2258 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2259 guint64 current_level_bytes = 0;
2261 MMPLAYER_RETURN_IF_FAIL(player);
2263 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2264 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2265 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2266 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2267 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2268 type = MM_PLAYER_STREAM_TYPE_TEXT;
2270 LOGE("can not enter here");
2274 LOGI("type: %d, buffer is full", type);
2276 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2278 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2280 if (player->media_stream_buffer_status_cb[type])
2281 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2283 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2287 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2289 mm_player_t *player = (mm_player_t*)user_data;
2290 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2294 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2295 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2296 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2297 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2298 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2299 type = MM_PLAYER_STREAM_TYPE_TEXT;
2301 LOGE("can not enter here");
2305 LOGD("type: %d, pos: %llu", type, position);
2306 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2308 if (player->media_stream_seek_data_cb[type])
2309 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2310 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2316 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2318 #define MAX_LEN_NAME 20
2320 gboolean ret = FALSE;
2321 GstPad *sinkpad = NULL;
2322 gchar *prefix = NULL;
2323 gchar dec_name[MAX_LEN_NAME] = {0};
2324 enum MainElementID elem_id = MMPLAYER_M_NUM;
2326 MMPlayerGstElement *mainbin = NULL;
2327 GstElement *decodebin = NULL;
2328 GstCaps *dec_caps = NULL;
2332 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2334 player->pipeline->mainbin, FALSE);
2335 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2337 mainbin = player->pipeline->mainbin;
2339 case MM_PLAYER_STREAM_TYPE_AUDIO:
2341 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2343 case MM_PLAYER_STREAM_TYPE_VIDEO:
2345 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2348 LOGE("invalid type %d", type);
2352 if (mainbin[elem_id].gst) {
2353 LOGE("elem(%d) is already created", elem_id);
2357 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2359 /* create decodebin */
2360 decodebin = gst_element_factory_make("decodebin", dec_name);
2362 LOGE("failed to create %s", dec_name);
2366 mainbin[elem_id].id = elem_id;
2367 mainbin[elem_id].gst = decodebin;
2369 /* raw pad handling signal */
2370 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2371 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2373 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2374 before looking for any elements that can handle that stream.*/
2375 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2376 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2378 /* This signal is emitted when a element is added to the bin.*/
2379 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2380 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2382 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2383 LOGE("failed to add new decodebin");
2387 dec_caps = gst_pad_query_caps(srcpad, NULL);
2389 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2390 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2391 gst_caps_unref(dec_caps);
2394 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2396 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2397 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2400 gst_object_unref(GST_OBJECT(sinkpad));
2402 gst_element_sync_state_with_parent(decodebin);
2408 gst_object_unref(GST_OBJECT(sinkpad));
2410 if (mainbin[elem_id].gst) {
2411 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2412 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2413 gst_object_unref(mainbin[elem_id].gst);
2414 mainbin[elem_id].gst = NULL;
2422 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2424 #define MAX_LEN_NAME 20
2425 MMPlayerGstElement *mainbin = NULL;
2426 gchar *prefix = NULL;
2427 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2429 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2430 GstElement *src = NULL, *queue = NULL;
2431 GstPad *srcpad = NULL;
2434 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2435 player->pipeline->mainbin, FALSE);
2437 mainbin = player->pipeline->mainbin;
2439 LOGD("type(%d) path is creating", type);
2441 case MM_PLAYER_STREAM_TYPE_AUDIO:
2443 if (mainbin[MMPLAYER_M_SRC].gst)
2444 src_id = MMPLAYER_M_2ND_SRC;
2446 src_id = MMPLAYER_M_SRC;
2447 queue_id = MMPLAYER_M_A_BUFFER;
2449 case MM_PLAYER_STREAM_TYPE_VIDEO:
2451 src_id = MMPLAYER_M_SRC;
2452 queue_id = MMPLAYER_M_V_BUFFER;
2454 case MM_PLAYER_STREAM_TYPE_TEXT:
2455 prefix = "subtitle";
2456 src_id = MMPLAYER_M_SUBSRC;
2457 queue_id = MMPLAYER_M_S_BUFFER;
2460 LOGE("invalid type %d", type);
2464 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2465 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2468 src = gst_element_factory_make("appsrc", src_name);
2470 LOGF("failed to create %s", src_name);
2474 mainbin[src_id].id = src_id;
2475 mainbin[src_id].gst = src;
2477 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2478 "caps", caps, NULL);
2480 /* size of many video frames are larger than default blocksize as 4096 */
2481 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2482 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2484 if (player->media_stream_buffer_max_size[type] > 0)
2485 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2487 if (player->media_stream_buffer_min_percent[type] > 0)
2488 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2490 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2491 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2493 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2494 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2495 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2496 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2497 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2498 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2501 queue = gst_element_factory_make("queue2", queue_name);
2503 LOGE("failed to create %s", queue_name);
2506 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2508 mainbin[queue_id].id = queue_id;
2509 mainbin[queue_id].gst = queue;
2511 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2512 LOGE("failed to add src");
2516 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2517 LOGE("failed to add queue");
2521 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2522 LOGE("failed to link src and queue");
2526 /* create decoder */
2527 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2529 LOGE("failed to get srcpad of queue");
2533 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2534 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2536 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2537 LOGE("failed to create decoder");
2538 gst_object_unref(GST_OBJECT(srcpad));
2542 gst_object_unref(GST_OBJECT(srcpad));
2546 if (mainbin[src_id].gst) {
2547 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2548 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2549 gst_object_unref(mainbin[src_id].gst);
2550 mainbin[src_id].gst = NULL;
2553 if (mainbin[queue_id].gst) {
2554 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2555 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2556 gst_object_unref(mainbin[queue_id].gst);
2557 mainbin[queue_id].gst = NULL;
2564 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2566 GstPad *sinkpad = NULL;
2567 GstCaps* caps = NULL;
2568 GstElement* new_element = NULL;
2569 GstStructure* str = NULL;
2570 const gchar* name = NULL;
2572 mm_player_t* player = (mm_player_t*) data;
2576 MMPLAYER_RETURN_IF_FAIL(element && pad);
2577 MMPLAYER_RETURN_IF_FAIL(player &&
2579 player->pipeline->mainbin);
2582 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2583 * num_dynamic_pad will decreased after creating a sinkbin.
2585 player->num_dynamic_pad++;
2586 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2588 caps = gst_pad_query_caps(pad, NULL);
2590 MMPLAYER_CHECK_NULL(caps);
2592 /* clear previous result*/
2593 player->have_dynamic_pad = FALSE;
2595 str = gst_caps_get_structure(caps, 0);
2598 LOGE("cannot get structure from caps.\n");
2602 name = gst_structure_get_name(str);
2604 LOGE("cannot get mimetype from structure.\n");
2608 if (strstr(name, "video")) {
2610 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2612 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2613 if (player->v_stream_caps) {
2614 gst_caps_unref(player->v_stream_caps);
2615 player->v_stream_caps = NULL;
2618 new_element = gst_element_factory_make("fakesink", NULL);
2619 player->num_dynamic_pad--;
2624 /* clear previous result*/
2625 player->have_dynamic_pad = FALSE;
2627 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2628 LOGE("failed to autoplug for caps");
2632 /* check if there's dynamic pad*/
2633 if (player->have_dynamic_pad) {
2634 LOGE("using pad caps assums there's no dynamic pad !\n");
2638 gst_caps_unref(caps);
2643 /* excute new_element if created*/
2645 LOGD("adding new element to pipeline\n");
2647 /* set state to READY before add to bin */
2648 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2650 /* add new element to the pipeline */
2651 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2652 LOGE("failed to add autoplug element to bin\n");
2656 /* get pad from element */
2657 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2659 LOGE("failed to get sinkpad from autoplug element\n");
2664 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2665 LOGE("failed to link autoplug element\n");
2669 gst_object_unref(sinkpad);
2672 /* run. setting PLAYING here since streamming source is live source */
2673 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2677 gst_caps_unref(caps);
2683 STATE_CHANGE_FAILED:
2685 /* FIXIT : take care if new_element has already added to pipeline */
2687 gst_object_unref(GST_OBJECT(new_element));
2690 gst_object_unref(GST_OBJECT(sinkpad));
2693 gst_caps_unref(caps);
2695 /* FIXIT : how to inform this error to MSL ????? */
2696 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2697 * then post an error to application
2702 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2704 mm_player_t* player = (mm_player_t*) data;
2708 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2709 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2710 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2711 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2713 * [1] audio and video will be dumped with filesink.
2714 * [2] autoplugging is done by just using pad caps.
2715 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2716 * and the video will be dumped via filesink.
2718 if (player->num_dynamic_pad == 0) {
2719 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2721 if (!__mmplayer_gst_remove_fakesink(player,
2722 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2723 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2724 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2725 * source element are not same. To overcome this situation, this function will called
2726 * several places and several times. Therefore, this is not an error case.
2731 /* create dot before error-return. for debugging */
2732 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2734 player->no_more_pad = TRUE;
2740 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2742 GstElement* element = NULL;
2743 gchar *user_agent = NULL;
2744 MMHandleType attrs = 0;
2747 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2749 /* get profile attribute */
2750 attrs = MMPLAYER_GET_ATTRS(player);
2752 LOGE("failed to get content attribute");
2756 element = gst_element_factory_make("rtspsrc", "rtsp source");
2758 LOGE("failed to create rtspsrc element");
2763 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2765 SECURE_LOGD("user_agent : %s", user_agent);
2767 /* setting property to streaming source */
2768 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2770 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2772 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2773 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2774 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2775 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2782 __mmplayer_gst_make_http_src(mm_player_t* player)
2784 GstElement* element = NULL;
2785 MMHandleType attrs = 0;
2786 gchar *user_agent, *cookies, **cookie_list;
2787 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2788 user_agent = cookies = NULL;
2792 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2794 /* get profile attribute */
2795 attrs = MMPLAYER_GET_ATTRS(player);
2797 LOGE("failed to get content attribute");
2801 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2803 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2805 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2810 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2811 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2813 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2814 http_timeout = player->ini.http_timeout;
2817 SECURE_LOGD("location : %s", player->profile.uri);
2818 SECURE_LOGD("cookies : %s", cookies);
2819 SECURE_LOGD("user_agent : %s", user_agent);
2820 LOGD("timeout : %d", http_timeout);
2822 /* setting property to streaming source */
2823 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2824 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2826 /* parsing cookies */
2827 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2828 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2829 g_strfreev(cookie_list);
2833 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2835 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2836 LOGW("[DASH] this is still experimental feature");
2843 __mmplayer_gst_make_file_src(mm_player_t* player)
2845 GstElement* element = NULL;
2848 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2850 LOGD("using filesrc for 'file://' handler");
2851 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2852 LOGE("failed to get storage info");
2856 element = gst_element_factory_make("filesrc", "source");
2858 LOGE("failed to create filesrc");
2862 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2868 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2870 mm_player_t *player = (mm_player_t *) data;
2872 g_return_val_if_fail(player, FALSE);
2873 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2875 gst_message_ref(msg);
2877 g_mutex_lock(&player->bus_msg_q_lock);
2878 g_queue_push_tail(player->bus_msg_q, msg);
2879 g_mutex_unlock(&player->bus_msg_q_lock);
2881 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2882 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2883 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2887 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2889 mm_player_t *player = (mm_player_t*)(data);
2890 GstMessage *msg = NULL;
2894 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2896 player->pipeline->mainbin &&
2897 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2900 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2902 LOGE("cannot get BUS from the pipeline");
2906 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2908 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2909 while (!player->bus_msg_thread_exit) {
2910 g_mutex_lock(&player->bus_msg_q_lock);
2911 msg = g_queue_pop_head(player->bus_msg_q);
2912 g_mutex_unlock(&player->bus_msg_q_lock);
2914 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2917 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2918 /* handle the gst msg */
2919 __mmplayer_gst_bus_msg_callback(msg, player);
2920 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2921 gst_message_unref(msg);
2924 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2925 gst_object_unref(GST_OBJECT(bus));
2932 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2934 gint64 dur_nsec = 0;
2937 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2939 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2940 return MM_ERROR_NONE;
2942 /* NOTE : duration cannot be zero except live streaming.
2943 * Since some element could have some timing problemn with quering duration, try again.
2945 if (player->duration == 0) {
2946 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2947 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2948 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2949 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2950 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2951 player->pending_seek.is_pending = TRUE;
2952 player->pending_seek.pos = position;
2953 player->seek_state = MMPLAYER_SEEK_NONE;
2954 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2955 return MM_ERROR_PLAYER_NO_OP;
2957 player->seek_state = MMPLAYER_SEEK_NONE;
2958 return MM_ERROR_PLAYER_SEEK;
2961 player->duration = dur_nsec;
2964 if (player->duration > 0 && player->duration < position) {
2965 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2966 return MM_ERROR_INVALID_ARGUMENT;
2970 return MM_ERROR_NONE;
2974 __mmplayer_gst_check_seekable(mm_player_t* player)
2976 GstQuery *query = NULL;
2977 gboolean seekable = FALSE;
2979 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2983 query = gst_query_new_seeking(GST_FORMAT_TIME);
2984 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2985 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2986 gst_query_unref(query);
2989 LOGW("non-seekable content");
2990 player->seek_state = MMPLAYER_SEEK_NONE;
2994 LOGW("failed to get seeking query");
2995 gst_query_unref(query); /* keep seeking operation */
3006 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
3008 GstState element_state = GST_STATE_VOID_PENDING;
3009 GstState element_pending_state = GST_STATE_VOID_PENDING;
3010 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3014 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3015 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3017 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3020 ret = gst_element_set_state(element, state);
3022 if (ret == GST_STATE_CHANGE_FAILURE) {
3023 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3025 /* dump state of all element */
3026 __mmplayer_dump_pipeline_state(player);
3028 return MM_ERROR_PLAYER_INTERNAL;
3031 /* return here so state transition to be done in async mode */
3033 LOGD("async state transition. not waiting for state complete.\n");
3034 return MM_ERROR_NONE;
3037 /* wait for state transition */
3038 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3040 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3041 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3042 GST_ELEMENT_NAME(element),
3043 gst_element_state_get_name(state), timeout);
3045 LOGE(" [%s] state : %s pending : %s \n",
3046 GST_ELEMENT_NAME(element),
3047 gst_element_state_get_name(element_state),
3048 gst_element_state_get_name(element_pending_state));
3050 /* dump state of all element */
3051 __mmplayer_dump_pipeline_state(player);
3053 return MM_ERROR_PLAYER_INTERNAL;
3056 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3060 return MM_ERROR_NONE;
3063 int __mmplayer_gst_start(mm_player_t* player)
3065 int ret = MM_ERROR_NONE;
3066 gboolean async = FALSE;
3070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3072 /* NOTE : if SetPosition was called before Start. do it now */
3073 /* streaming doesn't support it. so it should be always sync */
3074 /* !!create one more api to check if there is pending seek rather than checking variables */
3075 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3076 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3077 ret = __mmplayer_gst_pause(player, FALSE);
3078 if (ret != MM_ERROR_NONE) {
3079 LOGE("failed to set state to PAUSED for pending seek");
3083 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3084 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3085 LOGW("failed to seek pending postion. starting from the begin of content");
3088 LOGD("current state before doing transition");
3089 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3090 MMPLAYER_PRINT_STATE(player);
3092 /* set pipeline state to PLAYING */
3093 ret = __mmplayer_gst_set_state(player,
3094 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3096 if (ret == MM_ERROR_NONE) {
3097 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3099 LOGE("failed to set state to PLAYING");
3103 /* generating debug info before returning error */
3104 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3111 int __mmplayer_gst_stop(mm_player_t* player)
3113 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3114 MMHandleType attrs = 0;
3115 gboolean rewind = FALSE;
3117 int ret = MM_ERROR_NONE;
3121 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3122 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3124 LOGD("current state before doing transition");
3125 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3126 MMPLAYER_PRINT_STATE(player);
3128 attrs = MMPLAYER_GET_ATTRS(player);
3130 LOGE("cannot get content attribute\n");
3131 return MM_ERROR_PLAYER_INTERNAL;
3134 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3135 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3137 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3138 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3141 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3142 /* disable the async state transition because there could be no data in the pipeline */
3143 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3147 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3149 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3150 /* enable the async state transition as default operation */
3151 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3154 /* return if set_state has failed */
3155 if (ret != MM_ERROR_NONE) {
3156 LOGE("failed to set state.\n");
3162 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3163 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3164 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3165 LOGW("failed to rewind\n");
3166 ret = MM_ERROR_PLAYER_SEEK;
3171 player->sent_bos = FALSE;
3173 if (player->es_player_push_mode) //for cloudgame
3176 /* wait for seek to complete */
3177 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3178 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3179 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3181 LOGE("fail to stop player.\n");
3182 ret = MM_ERROR_PLAYER_INTERNAL;
3183 __mmplayer_dump_pipeline_state(player);
3186 /* generate dot file if enabled */
3187 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3194 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3196 int ret = MM_ERROR_NONE;
3200 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3201 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3203 LOGD("current state before doing transition");
3204 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3205 MMPLAYER_PRINT_STATE(player);
3207 /* set pipeline status to PAUSED */
3208 ret = __mmplayer_gst_set_state(player,
3209 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3211 if (FALSE == async) {
3212 if (ret != MM_ERROR_NONE) {
3213 GstMessage *msg = NULL;
3214 GTimer *timer = NULL;
3215 gdouble MAX_TIMEOUT_SEC = 3;
3217 LOGE("failed to set state to PAUSED");
3219 if (!player->bus_watcher) {
3220 LOGE("there is no bus msg thread. pipeline is shutting down.");
3224 if (player->msg_posted) {
3225 LOGE("error msg is already posted.");
3229 timer = g_timer_new();
3230 g_timer_start(timer);
3232 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3235 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3237 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3238 GError *error = NULL;
3240 /* parse error code */
3241 gst_message_parse_error(msg, &error, NULL);
3243 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3244 /* Note : the streaming error from the streaming source is handled
3245 * using __mmplayer_handle_streaming_error.
3247 __mmplayer_handle_streaming_error(player, msg);
3250 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3252 if (error->domain == GST_STREAM_ERROR)
3253 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3254 else if (error->domain == GST_RESOURCE_ERROR)
3255 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3256 else if (error->domain == GST_LIBRARY_ERROR)
3257 ret = __mmplayer_gst_handle_library_error(player, error->code);
3258 else if (error->domain == GST_CORE_ERROR)
3259 ret = __mmplayer_gst_handle_core_error(player, error->code);
3261 g_error_free(error);
3263 player->msg_posted = TRUE;
3265 gst_message_unref(msg);
3267 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3269 gst_object_unref(bus);
3270 g_timer_stop(timer);
3271 g_timer_destroy(timer);
3275 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3276 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3278 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3281 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3285 /* generate dot file before returning error */
3286 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3293 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3295 int ret = MM_ERROR_NONE;
3300 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3301 MM_ERROR_PLAYER_NOT_INITIALIZED);
3303 LOGD("current state before doing transition");
3304 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3305 MMPLAYER_PRINT_STATE(player);
3308 LOGD("do async state transition to PLAYING");
3310 /* set pipeline state to PLAYING */
3311 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3313 ret = __mmplayer_gst_set_state(player,
3314 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3315 if (ret != MM_ERROR_NONE) {
3316 LOGE("failed to set state to PLAYING");
3320 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3324 /* generate dot file */
3325 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3332 /* sending event to one of sinkelements */
3334 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3336 GstEvent * event2 = NULL;
3337 GList *sinks = NULL;
3338 gboolean res = FALSE;
3341 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3342 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3344 /* While adding subtitles in live feeds seek is getting called.
3345 Adding defensive check in framework layer.*/
3346 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3347 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3348 LOGE("Should not send seek event during live playback");
3353 if (player->play_subtitle)
3354 event2 = gst_event_copy((const GstEvent *)event);
3356 sinks = player->sink_elements;
3358 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3360 if (GST_IS_ELEMENT(sink)) {
3361 /* keep ref to the event */
3362 gst_event_ref(event);
3364 if ((res = gst_element_send_event(sink, event))) {
3365 LOGD("sending event[%s] to sink element [%s] success!\n",
3366 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3368 /* rtsp case, asyn_done is not called after seek during pause state */
3369 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3370 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3371 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3372 LOGD("RTSP seek completed, after pause state..\n");
3373 player->seek_state = MMPLAYER_SEEK_NONE;
3374 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3380 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3381 sinks = g_list_next(sinks);
3388 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3389 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3392 sinks = g_list_next(sinks);
3395 /* Note : Textbin is not linked to the video or audio bin.
3396 * It needs to send the event to the text sink seperatelly.
3398 if (player->play_subtitle && player->pipeline) {
3399 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3401 if (GST_IS_ELEMENT(text_sink)) {
3402 /* keep ref to the event */
3403 gst_event_ref(event2);
3405 if ((res = gst_element_send_event(text_sink, event2)))
3406 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3407 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3409 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3410 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3412 gst_event_unref(event2);
3416 gst_event_unref(event);
3424 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3425 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3426 gint64 cur, GstSeekType stop_type, gint64 stop)
3428 GstEvent* event = NULL;
3429 gboolean result = FALSE;
3433 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3435 if (player->pipeline && player->pipeline->textbin)
3436 __mmplayer_drop_subtitle(player, FALSE);
3438 event = gst_event_new_seek(rate, format, flags, cur_type,
3439 cur, stop_type, stop);
3441 result = __mmplayer_gst_send_event_to_sink(player, event);
3449 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3451 int ret = MM_ERROR_NONE;
3452 gint64 pos_nsec = 0;
3453 gboolean accurated = FALSE;
3454 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3458 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3460 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3461 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3464 ret = __mmplayer_gst_check_duration(player, position);
3465 if (ret != MM_ERROR_NONE) {
3466 LOGE("failed to check duration 0x%X", ret);
3467 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3470 if (!__mmplayer_gst_check_seekable(player))
3471 return MM_ERROR_PLAYER_NO_OP;
3473 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3474 position, player->playback_rate, player->duration);
3476 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3477 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3478 This causes problem is position calculation during normal pause resume scenarios also.
3479 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3480 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3481 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3482 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3483 LOGW("getting current position failed in seek");
3485 player->last_position = pos_nsec;
3486 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3489 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3490 LOGD("not completed seek");
3491 return MM_ERROR_PLAYER_DOING_SEEK;
3494 if (!internal_called)
3495 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3497 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3498 that's why set position through property. */
3499 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3500 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3501 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3502 (!player->videodec_linked) && (!player->audiodec_linked)) {
3504 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3505 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3507 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3508 player->seek_state = MMPLAYER_SEEK_NONE;
3509 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3511 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3513 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3515 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3517 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3518 GST_FORMAT_TIME, seek_flags,
3519 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3520 LOGE("failed to set position");
3525 /* NOTE : store last seeking point to overcome some bad operation
3526 * (returning zero when getting current position) of some elements
3528 player->last_position = position;
3530 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3531 if (player->playback_rate > 1.0)
3532 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3534 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3535 LOGD("buffering should be reset after seeking");
3536 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3537 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3541 return MM_ERROR_NONE;
3544 player->pending_seek.is_pending = TRUE;
3545 player->pending_seek.pos = position;
3547 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3548 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3549 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3550 player->pending_seek.pos);
3552 return MM_ERROR_NONE;
3555 player->seek_state = MMPLAYER_SEEK_NONE;
3556 return MM_ERROR_PLAYER_SEEK;
3560 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3562 #define TRICKPLAY_OFFSET GST_MSECOND
3564 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3565 gint64 pos_nsec = 0;
3566 gboolean ret = TRUE;
3568 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3569 MM_ERROR_PLAYER_NOT_INITIALIZED);
3571 current_state = MMPLAYER_CURRENT_STATE(player);
3573 /* NOTE : query position except paused state to overcome some bad operation
3574 * please refer to below comments in details
3576 if (current_state != MM_PLAYER_STATE_PAUSED)
3577 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3579 /* NOTE : get last point to overcome some bad operation of some elements
3580 *(returning zero when getting current position in paused state
3581 * and when failed to get postion during seeking
3583 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3584 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3586 if (player->playback_rate < 0.0)
3587 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3589 pos_nsec = player->last_position;
3592 pos_nsec = player->last_position;
3594 player->last_position = pos_nsec;
3596 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3599 if (player->duration > 0 && pos_nsec > player->duration)
3600 pos_nsec = player->duration;
3602 player->last_position = pos_nsec;
3605 *position = pos_nsec;
3607 return MM_ERROR_NONE;
3610 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3612 #define STREAMING_IS_FINISHED 0
3613 #define BUFFERING_MAX_PER 100
3614 #define DEFAULT_PER_VALUE -1
3615 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3617 MMPlayerGstElement *mainbin = NULL;
3618 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3619 gint64 buffered_total = 0;
3620 gint64 position = 0;
3621 gint buffered_sec = -1;
3622 GstBufferingMode mode = GST_BUFFERING_STREAM;
3623 gint64 content_size_time = player->duration;
3624 guint64 content_size_bytes = player->http_content_size;
3626 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3628 player->pipeline->mainbin,
3629 MM_ERROR_PLAYER_NOT_INITIALIZED);
3631 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3636 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3637 /* and rtsp is not ready yet. */
3638 LOGW("it's only used for http streaming case");
3639 return MM_ERROR_PLAYER_NO_OP;
3642 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3643 LOGW("Time format is not supported yet");
3644 return MM_ERROR_INVALID_ARGUMENT;
3647 if (content_size_time <= 0 || content_size_bytes <= 0) {
3648 LOGW("there is no content size");
3649 return MM_ERROR_NONE;
3652 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3653 LOGW("fail to get current position");
3654 return MM_ERROR_NONE;
3657 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3658 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3660 mainbin = player->pipeline->mainbin;
3661 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3663 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3664 GstQuery *query = NULL;
3665 gint byte_in_rate = 0, byte_out_rate = 0;
3666 gint64 estimated_total = 0;
3668 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3669 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3670 LOGW("fail to get buffering query from queue2");
3672 gst_query_unref(query);
3673 return MM_ERROR_NONE;
3676 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3677 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3679 if (mode == GST_BUFFERING_STREAM) {
3680 /* using only queue in case of push mode(ts / mp3) */
3681 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3682 GST_FORMAT_BYTES, &buffered_total)) {
3683 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3684 stop_per = 100 * buffered_total / content_size_bytes;
3687 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3689 guint num_of_ranges = 0;
3690 gint64 start_byte = 0, stop_byte = 0;
3692 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3693 if (estimated_total != STREAMING_IS_FINISHED) {
3694 /* buffered size info from queue2 */
3695 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3696 for (idx = 0; idx < num_of_ranges; idx++) {
3697 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3698 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3700 buffered_total += (stop_byte - start_byte);
3703 stop_per = BUFFERING_MAX_PER;
3705 gst_query_unref(query);
3708 if (stop_per == DEFAULT_PER_VALUE) {
3709 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3711 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3713 /* buffered size info from multiqueue */
3714 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3715 guint curr_size_bytes = 0;
3716 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3717 "curr-size-bytes", &curr_size_bytes, NULL);
3718 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3719 buffered_total += curr_size_bytes;
3722 if (avg_byterate > 0)
3723 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3724 else if (player->total_maximum_bitrate > 0)
3725 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3726 else if (player->total_bitrate > 0)
3727 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3729 if (buffered_sec >= 0)
3730 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3734 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3735 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3737 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3738 buffered_total, buffered_sec, *start_pos, *stop_pos);
3740 return MM_ERROR_NONE;
3743 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3745 GstElement* element = NULL;
3748 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3749 player->pipeline->mainbin, NULL);
3751 /* setup source for gapless play */
3752 switch (player->profile.uri_type) {
3754 case MM_PLAYER_URI_TYPE_FILE:
3755 element = __mmplayer_gst_make_file_src(player);
3757 case MM_PLAYER_URI_TYPE_URL_HTTP:
3758 element = __mmplayer_gst_make_http_src(player);
3761 LOGE("not support uri type %d", player->profile.uri_type);
3766 LOGE("failed to create source element");
3774 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3776 MMHandleType attrs = 0;
3779 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3780 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3782 /* get profile attribute */
3783 attrs = MMPLAYER_GET_ATTRS(player);
3785 LOGE("failed to get content attribute");
3786 return MM_ERROR_PLAYER_INTERNAL;
3789 SECURE_LOGD("uri : %s", player->profile.uri);
3791 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3792 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3793 LOGE("failed to commit");
3795 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3796 return MM_ERROR_PLAYER_INTERNAL;
3798 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3799 return MM_ERROR_PLAYER_INTERNAL;
3801 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3802 return MM_ERROR_PLAYER_INTERNAL;
3805 return MM_ERROR_NONE;
3808 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3810 MMPlayerGstElement *mainbin = NULL;
3811 GstElement *pd_src = NULL;
3812 GstElement *pd_queue = NULL;
3813 GstElement *pd_decodebin = NULL;
3814 GList* element_bucket = NULL;
3815 MMHandleType attrs = 0;
3817 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3820 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3821 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3823 /* get profile attribute */
3824 attrs = MMPLAYER_GET_ATTRS(player);
3826 LOGE("failed to get content attribute");
3827 return MM_ERROR_PLAYER_INTERNAL;
3830 LOGD("http playback with progressive download : %d", player->pd_mode);
3832 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3833 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3834 MMPLAYER_FREEIF(player->pd_file_save_path);
3836 SECURE_LOGD("PD Location : %s", path);
3838 LOGE("filed to find pd location");
3839 return MM_ERROR_PLAYER_INTERNAL;
3842 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3843 LOGE("failed to get storage info");
3844 return MM_ERROR_PLAYER_INTERNAL;
3846 player->pd_file_save_path = g_strdup(path);
3849 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3851 LOGE("failed to create PD push source");
3852 return MM_ERROR_PLAYER_INTERNAL;
3855 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3856 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3858 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3860 mainbin = player->pipeline->mainbin;
3862 /* take source element */
3863 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3864 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3865 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3868 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3869 pd_queue = gst_element_factory_make("queue2", "queue2");
3871 LOGE("failed to create pd buffer element");
3876 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3877 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3878 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3880 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3882 player->streamer->is_pd_mode = TRUE;
3884 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3885 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3886 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3888 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3889 if (!pd_decodebin) {
3890 LOGE("failed to create decodebin");
3894 /* default size of mq in decodebin is 2M
3895 * but it can cause blocking issue during seeking depends on content. */
3896 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3898 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3899 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3901 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3903 /* add elements to pipeline */
3904 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3905 LOGE("failed to add elements to pipeline");
3909 /* linking elements in the bucket by added order. */
3910 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3911 LOGE("failed to link some elements");
3915 g_list_free(element_bucket);
3918 return MM_ERROR_NONE;
3921 MMPLAYER_FREEIF(player->pd_file_save_path);
3922 g_list_free(element_bucket);
3924 if (mainbin[MMPLAYER_M_SRC].gst)
3925 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3927 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3928 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3930 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3931 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3933 mainbin[MMPLAYER_M_SRC].gst = NULL;
3934 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3935 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3937 return MM_ERROR_PLAYER_INTERNAL;
3940 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3942 MMPlayerGstElement *mainbin = NULL;
3943 GstElement* src_elem = NULL;
3944 GstElement *autoplug_elem = NULL;
3945 GList* element_bucket = NULL;
3946 MMHandleType attrs = 0;
3947 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3950 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3951 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3953 /* get profile attribute */
3954 attrs = MMPLAYER_GET_ATTRS(player);
3956 LOGE("failed to get content attribute");
3957 return MM_ERROR_PLAYER_INTERNAL;
3960 LOGD("uri type %d", player->profile.uri_type);
3962 /* create source element */
3963 switch (player->profile.uri_type) {
3964 case MM_PLAYER_URI_TYPE_URL_RTSP:
3965 src_elem = __mmplayer_gst_make_rtsp_src(player);
3967 case MM_PLAYER_URI_TYPE_URL_HTTP:
3968 src_elem = __mmplayer_gst_make_http_src(player);
3970 case MM_PLAYER_URI_TYPE_FILE:
3971 src_elem = __mmplayer_gst_make_file_src(player);
3973 case MM_PLAYER_URI_TYPE_SS:
3975 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3976 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3978 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3982 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3983 LOGD("get timeout from ini");
3984 http_timeout = player->ini.http_timeout;
3987 /* setting property to streaming source */
3988 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3991 case MM_PLAYER_URI_TYPE_MEM:
3993 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3995 src_elem = gst_element_factory_make("appsrc", "mem-source");
3997 LOGE("failed to create appsrc element");
4001 g_object_set(src_elem, "stream-type", stream_type,
4002 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4004 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4005 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4006 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4007 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4011 LOGE("not support uri type");
4016 LOGE("failed to create source element");
4017 return MM_ERROR_PLAYER_INTERNAL;
4020 mainbin = player->pipeline->mainbin;
4022 /* take source element */
4023 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4025 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4026 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4027 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4029 /* create next element for auto-plugging */
4030 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4031 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4032 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4033 if (!autoplug_elem) {
4034 LOGE("failed to create typefind element");
4038 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4039 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4040 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4041 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4042 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4043 if (!autoplug_elem) {
4044 LOGE("failed to create decodebin");
4048 /* default size of mq in decodebin is 2M
4049 * but it can cause blocking issue during seeking depends on content. */
4050 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4053 if (autoplug_elem) {
4054 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4055 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4056 mainbin[autoplug_elem_id].gst = autoplug_elem;
4058 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4061 /* add elements to pipeline */
4062 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4063 LOGE("failed to add elements to pipeline");
4067 /* linking elements in the bucket by added order. */
4068 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4069 LOGE("failed to link some elements");
4073 /* FIXME: need to check whether this is required or not. */
4074 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4075 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4076 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4077 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4079 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4080 LOGE("failed to create fakesink");
4083 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4085 /* take ownership of fakesink. we are reusing it */
4086 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4088 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4089 LOGE("failed to add fakesink to bin");
4090 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4095 g_list_free(element_bucket);
4098 return MM_ERROR_NONE;
4101 g_list_free(element_bucket);
4103 if (mainbin[MMPLAYER_M_SRC].gst)
4104 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4106 if (mainbin[autoplug_elem_id].gst)
4107 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4109 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4110 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4112 mainbin[MMPLAYER_M_SRC].gst = NULL;
4113 mainbin[autoplug_elem_id].gst = NULL;
4114 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4116 return MM_ERROR_PLAYER_INTERNAL;
4119 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4122 MMPlayerGstElement *mainbin = NULL;
4125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4126 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4128 mainbin = player->pipeline->mainbin;
4130 /* connect bus callback */
4131 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4133 LOGE("cannot get bus from pipeline");
4134 return MM_ERROR_PLAYER_INTERNAL;
4137 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4138 player->context.thread_default = g_main_context_get_thread_default();
4139 if (player->context.thread_default == NULL) {
4140 player->context.thread_default = g_main_context_default();
4141 LOGD("thread-default context is the global default context");
4143 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4145 /* set sync handler to get tag synchronously */
4146 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4147 gst_object_unref(GST_OBJECT(bus));
4149 /* create gst bus_msb_cb thread */
4150 g_mutex_init(&player->bus_msg_thread_mutex);
4151 g_cond_init(&player->bus_msg_thread_cond);
4152 player->bus_msg_thread_exit = FALSE;
4153 player->bus_msg_thread =
4154 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4155 if (!player->bus_msg_thread) {
4156 LOGE("failed to create gst BUS msg thread");
4157 g_mutex_clear(&player->bus_msg_thread_mutex);
4158 g_cond_clear(&player->bus_msg_thread_cond);
4159 return MM_ERROR_PLAYER_INTERNAL;
4163 return MM_ERROR_NONE;