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) {
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)
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) && (!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_TAG:
2128 __mmplayer_gst_extract_tag_from_msg(player, message);
2132 GstTagList *tags = NULL;
2134 gst_message_parse_tag(message, &tags);
2136 LOGE("TAGS received from element \"%s\".\n",
2137 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2139 gst_tag_list_foreach(tags, print_tag, NULL);
2140 gst_tag_list_free(tags);
2148 case GST_MESSAGE_DURATION_CHANGED:
2149 __mmplayer_gst_handle_duration(player, message);
2151 case GST_MESSAGE_ASYNC_DONE:
2152 /* NOTE:Don't call gst_callback directly
2153 * because previous frame can be showed even though this message is received for seek.
2156 reply = GST_BUS_PASS;
2160 if (reply == GST_BUS_DROP)
2161 gst_message_unref(message);
2167 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2169 GstElement *appsrc = element;
2170 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2171 GstBuffer *buffer = NULL;
2172 GstFlowReturn ret = GST_FLOW_OK;
2175 MMPLAYER_RETURN_IF_FAIL(element);
2176 MMPLAYER_RETURN_IF_FAIL(buf);
2178 buffer = gst_buffer_new();
2180 if (buf->offset < 0 || buf->len < 0) {
2181 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2185 if (buf->offset >= buf->len) {
2186 LOGD("call eos appsrc");
2187 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2191 if (buf->len - buf->offset < size)
2192 len = buf->len - buf->offset;
2194 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2195 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2196 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2198 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2199 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2205 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2207 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2209 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2211 buf->offset = (int)size;
2217 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2219 mm_player_t *player = (mm_player_t*)user_data;
2220 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2221 guint64 current_level_bytes = 0;
2223 MMPLAYER_RETURN_IF_FAIL(player);
2225 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2226 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2227 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2228 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2229 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2230 type = MM_PLAYER_STREAM_TYPE_TEXT;
2232 LOGE("can not enter here");
2236 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2238 LOGI("type: %d, level: %llu", type, current_level_bytes);
2240 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2241 if (player->media_stream_buffer_status_cb[type])
2242 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2243 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2247 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2249 mm_player_t *player = (mm_player_t*)user_data;
2250 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2251 guint64 current_level_bytes = 0;
2253 MMPLAYER_RETURN_IF_FAIL(player);
2255 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2256 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2257 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2258 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2259 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2260 type = MM_PLAYER_STREAM_TYPE_TEXT;
2262 LOGE("can not enter here");
2266 LOGI("type: %d, buffer is full", type);
2268 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2270 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2272 if (player->media_stream_buffer_status_cb[type])
2273 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2275 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2279 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2281 mm_player_t *player = (mm_player_t*)user_data;
2282 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2284 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2286 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2287 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2288 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2289 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2290 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2291 type = MM_PLAYER_STREAM_TYPE_TEXT;
2293 LOGE("can not enter here");
2297 LOGD("type: %d, pos: %llu", type, position);
2298 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2300 if (player->media_stream_seek_data_cb[type])
2301 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2302 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2308 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2310 #define MAX_LEN_NAME 20
2312 gboolean ret = FALSE;
2313 GstPad *sinkpad = NULL;
2314 gchar *prefix = NULL;
2315 gchar dec_name[MAX_LEN_NAME] = {0};
2316 enum MainElementID elem_id = MMPLAYER_M_NUM;
2318 MMPlayerGstElement *mainbin = NULL;
2319 GstElement *decodebin = NULL;
2320 GstCaps *dec_caps = NULL;
2324 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2326 player->pipeline->mainbin, FALSE);
2327 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2329 mainbin = player->pipeline->mainbin;
2331 case MM_PLAYER_STREAM_TYPE_AUDIO:
2333 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2335 case MM_PLAYER_STREAM_TYPE_VIDEO:
2337 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2340 LOGE("invalid type %d", type);
2344 if (mainbin[elem_id].gst) {
2345 LOGE("elem(%d) is already created", elem_id);
2349 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2351 /* create decodebin */
2352 decodebin = gst_element_factory_make("decodebin", dec_name);
2354 LOGE("failed to create %s", dec_name);
2358 mainbin[elem_id].id = elem_id;
2359 mainbin[elem_id].gst = decodebin;
2361 /* raw pad handling signal */
2362 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2363 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2365 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2366 before looking for any elements that can handle that stream.*/
2367 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2368 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2370 /* This signal is emitted when a element is added to the bin.*/
2371 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2372 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2374 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2375 LOGE("failed to add new decodebin");
2379 dec_caps = gst_pad_query_caps(srcpad, NULL);
2381 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2382 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2383 gst_caps_unref(dec_caps);
2386 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2388 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2389 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2392 gst_object_unref(GST_OBJECT(sinkpad));
2394 gst_element_sync_state_with_parent(decodebin);
2400 gst_object_unref(GST_OBJECT(sinkpad));
2402 if (mainbin[elem_id].gst) {
2403 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2404 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2405 gst_object_unref(mainbin[elem_id].gst);
2406 mainbin[elem_id].gst = NULL;
2414 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2416 #define MAX_LEN_NAME 20
2417 MMPlayerGstElement *mainbin = NULL;
2418 gchar *prefix = NULL;
2419 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2421 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2422 GstElement *src = NULL, *queue = NULL;
2423 GstPad *srcpad = NULL;
2426 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2427 player->pipeline->mainbin, FALSE);
2429 mainbin = player->pipeline->mainbin;
2431 LOGD("type(%d) path is creating", type);
2433 case MM_PLAYER_STREAM_TYPE_AUDIO:
2435 if (mainbin[MMPLAYER_M_SRC].gst)
2436 src_id = MMPLAYER_M_2ND_SRC;
2438 src_id = MMPLAYER_M_SRC;
2439 queue_id = MMPLAYER_M_A_BUFFER;
2441 case MM_PLAYER_STREAM_TYPE_VIDEO:
2443 src_id = MMPLAYER_M_SRC;
2444 queue_id = MMPLAYER_M_V_BUFFER;
2446 case MM_PLAYER_STREAM_TYPE_TEXT:
2447 prefix = "subtitle";
2448 src_id = MMPLAYER_M_SUBSRC;
2449 queue_id = MMPLAYER_M_S_BUFFER;
2452 LOGE("invalid type %d", type);
2456 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2457 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2460 src = gst_element_factory_make("appsrc", src_name);
2462 LOGF("failed to create %s", src_name);
2466 mainbin[src_id].id = src_id;
2467 mainbin[src_id].gst = src;
2469 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2470 "caps", caps, NULL);
2472 /* size of many video frames are larger than default blocksize as 4096 */
2473 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2474 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2476 if (player->media_stream_buffer_max_size[type] > 0)
2477 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2479 if (player->media_stream_buffer_min_percent[type] > 0)
2480 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2482 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2483 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2485 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2486 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2487 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2488 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2489 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2490 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2493 queue = gst_element_factory_make("queue2", queue_name);
2495 LOGE("failed to create %s", queue_name);
2498 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2500 mainbin[queue_id].id = queue_id;
2501 mainbin[queue_id].gst = queue;
2503 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2504 LOGE("failed to add src");
2508 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2509 LOGE("failed to add queue");
2513 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2514 LOGE("failed to link src and queue");
2518 /* create decoder */
2519 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2521 LOGE("failed to get srcpad of queue");
2525 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2526 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2528 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2529 LOGE("failed to create decoder");
2530 gst_object_unref(GST_OBJECT(srcpad));
2534 gst_object_unref(GST_OBJECT(srcpad));
2538 if (mainbin[src_id].gst) {
2539 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2540 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2541 gst_object_unref(mainbin[src_id].gst);
2542 mainbin[src_id].gst = NULL;
2545 if (mainbin[queue_id].gst) {
2546 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2547 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2548 gst_object_unref(mainbin[queue_id].gst);
2549 mainbin[queue_id].gst = NULL;
2556 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2558 GstPad *sinkpad = NULL;
2559 GstCaps *caps = NULL;
2560 GstElement *new_element = NULL;
2561 GstStructure *str = NULL;
2562 const gchar *name = NULL;
2563 gboolean caps_ret = TRUE;
2565 mm_player_t *player = (mm_player_t*) data;
2569 MMPLAYER_RETURN_IF_FAIL(element && pad);
2570 MMPLAYER_RETURN_IF_FAIL(player &&
2572 player->pipeline->mainbin);
2574 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2578 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2579 * num_dynamic_pad will decreased after creating a sinkbin.
2581 player->num_dynamic_pad++;
2582 LOGD("stream count inc : %d", player->num_dynamic_pad);
2584 /* clear previous result*/
2585 player->have_dynamic_pad = FALSE;
2587 if (strstr(name, "video")) {
2589 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2591 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2592 if (player->v_stream_caps) {
2593 gst_caps_unref(player->v_stream_caps);
2594 player->v_stream_caps = NULL;
2597 new_element = gst_element_factory_make("fakesink", NULL);
2598 player->num_dynamic_pad--;
2603 /* clear previous result*/
2604 player->have_dynamic_pad = FALSE;
2606 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2607 LOGE("failed to autoplug for caps");
2611 /* check if there's dynamic pad*/
2612 if (player->have_dynamic_pad) {
2613 LOGE("using pad caps assums there's no dynamic pad !\n");
2617 gst_caps_unref(caps);
2622 /* excute new_element if created*/
2624 LOGD("adding new element to pipeline\n");
2626 /* set state to READY before add to bin */
2627 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2629 /* add new element to the pipeline */
2630 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2631 LOGE("failed to add autoplug element to bin\n");
2635 /* get pad from element */
2636 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2638 LOGE("failed to get sinkpad from autoplug element\n");
2643 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2644 LOGE("failed to link autoplug element\n");
2648 gst_object_unref(sinkpad);
2651 /* run. setting PLAYING here since streamming source is live source */
2652 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2656 gst_caps_unref(caps);
2662 STATE_CHANGE_FAILED:
2664 /* FIXIT : take care if new_element has already added to pipeline */
2666 gst_object_unref(GST_OBJECT(new_element));
2669 gst_object_unref(GST_OBJECT(sinkpad));
2672 gst_caps_unref(caps);
2674 /* FIXIT : how to inform this error to MSL ????? */
2675 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2676 * then post an error to application
2681 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2683 mm_player_t* player = (mm_player_t*) data;
2687 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2688 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2689 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2690 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2692 * [1] audio and video will be dumped with filesink.
2693 * [2] autoplugging is done by just using pad caps.
2694 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2695 * and the video will be dumped via filesink.
2697 if (player->num_dynamic_pad == 0) {
2698 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2700 if (!__mmplayer_gst_remove_fakesink(player,
2701 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2702 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2703 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2704 * source element are not same. To overcome this situation, this function will called
2705 * several places and several times. Therefore, this is not an error case.
2710 /* create dot before error-return. for debugging */
2711 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2713 player->no_more_pad = TRUE;
2719 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2721 GstElement* element = NULL;
2722 gchar *user_agent = NULL;
2723 MMHandleType attrs = 0;
2726 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2728 /* get profile attribute */
2729 attrs = MMPLAYER_GET_ATTRS(player);
2731 LOGE("failed to get content attribute");
2735 element = gst_element_factory_make("rtspsrc", "rtsp source");
2737 LOGE("failed to create rtspsrc element");
2742 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2744 SECURE_LOGD("user_agent : %s", user_agent);
2746 /* setting property to streaming source */
2747 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2749 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2751 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2752 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2753 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2754 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2761 __mmplayer_gst_make_http_src(mm_player_t* player)
2763 GstElement* element = NULL;
2764 MMHandleType attrs = 0;
2765 gchar *user_agent, *cookies, **cookie_list;
2766 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2767 user_agent = cookies = NULL;
2771 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2773 /* get profile attribute */
2774 attrs = MMPLAYER_GET_ATTRS(player);
2776 LOGE("failed to get content attribute");
2780 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2782 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2784 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2789 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2790 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2792 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2793 http_timeout = player->ini.http_timeout;
2796 SECURE_LOGD("location : %s", player->profile.uri);
2797 SECURE_LOGD("cookies : %s", cookies);
2798 SECURE_LOGD("user_agent : %s", user_agent);
2799 LOGD("timeout : %d", http_timeout);
2801 /* setting property to streaming source */
2802 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2803 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2805 /* parsing cookies */
2806 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2807 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2808 g_strfreev(cookie_list);
2812 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2814 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2815 LOGW("[DASH] this is still experimental feature");
2822 __mmplayer_gst_make_file_src(mm_player_t* player)
2824 GstElement* element = NULL;
2827 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2829 LOGD("using filesrc for 'file://' handler");
2830 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2831 LOGE("failed to get storage info");
2835 element = gst_element_factory_make("filesrc", "source");
2837 LOGE("failed to create filesrc");
2841 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2847 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2849 mm_player_t *player = (mm_player_t *) data;
2851 g_return_val_if_fail(player, FALSE);
2852 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2854 gst_message_ref(msg);
2856 g_mutex_lock(&player->bus_msg_q_lock);
2857 g_queue_push_tail(player->bus_msg_q, msg);
2858 g_mutex_unlock(&player->bus_msg_q_lock);
2860 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2861 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2862 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2866 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2868 mm_player_t *player = (mm_player_t*)(data);
2869 GstMessage *msg = NULL;
2873 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2875 player->pipeline->mainbin &&
2876 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2879 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2881 LOGE("cannot get BUS from the pipeline");
2885 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2887 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2888 while (!player->bus_msg_thread_exit) {
2889 g_mutex_lock(&player->bus_msg_q_lock);
2890 msg = g_queue_pop_head(player->bus_msg_q);
2891 g_mutex_unlock(&player->bus_msg_q_lock);
2893 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2896 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2897 /* handle the gst msg */
2898 __mmplayer_gst_bus_msg_callback(msg, player);
2899 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2900 gst_message_unref(msg);
2903 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2904 gst_object_unref(GST_OBJECT(bus));
2911 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2913 gint64 dur_nsec = 0;
2916 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2918 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2919 return MM_ERROR_NONE;
2921 /* NOTE : duration cannot be zero except live streaming.
2922 * Since some element could have some timing problemn with quering duration, try again.
2924 if (player->duration == 0) {
2925 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2926 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2927 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2928 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2929 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2930 player->pending_seek.is_pending = TRUE;
2931 player->pending_seek.pos = position;
2932 player->seek_state = MMPLAYER_SEEK_NONE;
2933 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2934 return MM_ERROR_PLAYER_NO_OP;
2936 player->seek_state = MMPLAYER_SEEK_NONE;
2937 return MM_ERROR_PLAYER_SEEK;
2940 player->duration = dur_nsec;
2943 if (player->duration > 0 && player->duration < position) {
2944 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2945 return MM_ERROR_INVALID_ARGUMENT;
2949 return MM_ERROR_NONE;
2953 __mmplayer_gst_check_seekable(mm_player_t* player)
2955 GstQuery *query = NULL;
2956 gboolean seekable = FALSE;
2958 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2962 query = gst_query_new_seeking(GST_FORMAT_TIME);
2963 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2964 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2965 gst_query_unref(query);
2968 LOGW("non-seekable content");
2969 player->seek_state = MMPLAYER_SEEK_NONE;
2973 LOGW("failed to get seeking query");
2974 gst_query_unref(query); /* keep seeking operation */
2985 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2987 GstState element_state = GST_STATE_VOID_PENDING;
2988 GstState element_pending_state = GST_STATE_VOID_PENDING;
2989 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2994 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2996 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2999 ret = gst_element_set_state(element, state);
3001 if (ret == GST_STATE_CHANGE_FAILURE) {
3002 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3004 /* dump state of all element */
3005 __mmplayer_dump_pipeline_state(player);
3007 return MM_ERROR_PLAYER_INTERNAL;
3010 /* return here so state transition to be done in async mode */
3012 LOGD("async state transition. not waiting for state complete.\n");
3013 return MM_ERROR_NONE;
3016 /* wait for state transition */
3017 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3019 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3020 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3021 GST_ELEMENT_NAME(element),
3022 gst_element_state_get_name(state), timeout);
3024 LOGE(" [%s] state : %s pending : %s \n",
3025 GST_ELEMENT_NAME(element),
3026 gst_element_state_get_name(element_state),
3027 gst_element_state_get_name(element_pending_state));
3029 /* dump state of all element */
3030 __mmplayer_dump_pipeline_state(player);
3032 return MM_ERROR_PLAYER_INTERNAL;
3035 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3039 return MM_ERROR_NONE;
3042 int __mmplayer_gst_start(mm_player_t* player)
3044 int ret = MM_ERROR_NONE;
3045 gboolean async = FALSE;
3049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3051 /* NOTE : if SetPosition was called before Start. do it now */
3052 /* streaming doesn't support it. so it should be always sync */
3053 /* !!create one more api to check if there is pending seek rather than checking variables */
3054 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3055 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3056 ret = __mmplayer_gst_pause(player, FALSE);
3057 if (ret != MM_ERROR_NONE) {
3058 LOGE("failed to set state to PAUSED for pending seek");
3062 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3063 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3064 LOGW("failed to seek pending postion. starting from the begin of content");
3067 LOGD("current state before doing transition");
3068 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3069 MMPLAYER_PRINT_STATE(player);
3071 /* set pipeline state to PLAYING */
3072 ret = __mmplayer_gst_set_state(player,
3073 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3075 if (ret == MM_ERROR_NONE) {
3076 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3078 LOGE("failed to set state to PLAYING");
3082 /* generating debug info before returning error */
3083 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3090 int __mmplayer_gst_stop(mm_player_t* player)
3092 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3093 MMHandleType attrs = 0;
3094 gboolean rewind = FALSE;
3096 int ret = MM_ERROR_NONE;
3100 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3101 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3103 LOGD("current state before doing transition");
3104 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3105 MMPLAYER_PRINT_STATE(player);
3107 attrs = MMPLAYER_GET_ATTRS(player);
3109 LOGE("cannot get content attribute\n");
3110 return MM_ERROR_PLAYER_INTERNAL;
3113 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3114 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3116 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3117 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3120 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3121 /* disable the async state transition because there could be no data in the pipeline */
3122 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3126 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3128 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3129 /* enable the async state transition as default operation */
3130 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3133 /* return if set_state has failed */
3134 if (ret != MM_ERROR_NONE) {
3135 LOGE("failed to set state.\n");
3141 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3142 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3143 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3144 LOGW("failed to rewind\n");
3145 ret = MM_ERROR_PLAYER_SEEK;
3150 player->sent_bos = FALSE;
3152 if (player->es_player_push_mode) //for cloudgame
3155 /* wait for seek to complete */
3156 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3157 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3158 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3160 LOGE("fail to stop player.\n");
3161 ret = MM_ERROR_PLAYER_INTERNAL;
3162 __mmplayer_dump_pipeline_state(player);
3165 /* generate dot file if enabled */
3166 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3173 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3175 int ret = MM_ERROR_NONE;
3179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3180 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3182 LOGD("current state before doing transition");
3183 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3184 MMPLAYER_PRINT_STATE(player);
3186 /* set pipeline status to PAUSED */
3187 ret = __mmplayer_gst_set_state(player,
3188 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3190 if (FALSE == async) {
3191 if (ret != MM_ERROR_NONE) {
3192 GstMessage *msg = NULL;
3193 GTimer *timer = NULL;
3194 gdouble MAX_TIMEOUT_SEC = 3;
3196 LOGE("failed to set state to PAUSED");
3198 if (!player->bus_watcher) {
3199 LOGE("there is no bus msg thread. pipeline is shutting down.");
3203 if (player->msg_posted) {
3204 LOGE("error msg is already posted.");
3208 timer = g_timer_new();
3209 g_timer_start(timer);
3211 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3214 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3216 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3217 GError *error = NULL;
3219 /* parse error code */
3220 gst_message_parse_error(msg, &error, NULL);
3222 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3223 /* Note : the streaming error from the streaming source is handled
3224 * using __mmplayer_handle_streaming_error.
3226 __mmplayer_handle_streaming_error(player, msg);
3229 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3231 if (error->domain == GST_STREAM_ERROR)
3232 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3233 else if (error->domain == GST_RESOURCE_ERROR)
3234 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3235 else if (error->domain == GST_LIBRARY_ERROR)
3236 ret = __mmplayer_gst_handle_library_error(player, error->code);
3237 else if (error->domain == GST_CORE_ERROR)
3238 ret = __mmplayer_gst_handle_core_error(player, error->code);
3240 g_error_free(error);
3242 player->msg_posted = TRUE;
3244 gst_message_unref(msg);
3246 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3248 gst_object_unref(bus);
3249 g_timer_stop(timer);
3250 g_timer_destroy(timer);
3254 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3255 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3257 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3260 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3264 /* generate dot file before returning error */
3265 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3272 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3274 int ret = MM_ERROR_NONE;
3279 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3280 MM_ERROR_PLAYER_NOT_INITIALIZED);
3282 LOGD("current state before doing transition");
3283 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3284 MMPLAYER_PRINT_STATE(player);
3287 LOGD("do async state transition to PLAYING");
3289 /* set pipeline state to PLAYING */
3290 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3292 ret = __mmplayer_gst_set_state(player,
3293 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3294 if (ret != MM_ERROR_NONE) {
3295 LOGE("failed to set state to PLAYING");
3299 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3303 /* generate dot file */
3304 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3311 /* sending event to one of sinkelements */
3313 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3315 GstEvent * event2 = NULL;
3316 GList *sinks = NULL;
3317 gboolean res = FALSE;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3321 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3323 /* While adding subtitles in live feeds seek is getting called.
3324 Adding defensive check in framework layer.*/
3325 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3326 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3327 LOGE("Should not send seek event during live playback");
3332 if (player->play_subtitle)
3333 event2 = gst_event_copy((const GstEvent *)event);
3335 sinks = player->sink_elements;
3337 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3339 if (GST_IS_ELEMENT(sink)) {
3340 /* keep ref to the event */
3341 gst_event_ref(event);
3343 if ((res = gst_element_send_event(sink, event))) {
3344 LOGD("sending event[%s] to sink element [%s] success!\n",
3345 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3347 /* rtsp case, asyn_done is not called after seek during pause state */
3348 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3349 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3350 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3351 LOGD("RTSP seek completed, after pause state..\n");
3352 player->seek_state = MMPLAYER_SEEK_NONE;
3353 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3359 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3360 sinks = g_list_next(sinks);
3367 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3368 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3371 sinks = g_list_next(sinks);
3374 /* Note : Textbin is not linked to the video or audio bin.
3375 * It needs to send the event to the text sink seperatelly.
3377 if (player->play_subtitle && player->pipeline) {
3378 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3380 if (GST_IS_ELEMENT(text_sink)) {
3381 /* keep ref to the event */
3382 gst_event_ref(event2);
3384 if ((res = gst_element_send_event(text_sink, event2)))
3385 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3386 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3388 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3389 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3391 gst_event_unref(event2);
3395 gst_event_unref(event);
3403 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3404 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3405 gint64 cur, GstSeekType stop_type, gint64 stop)
3407 GstEvent* event = NULL;
3408 gboolean result = FALSE;
3412 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3414 if (player->pipeline && player->pipeline->textbin)
3415 __mmplayer_drop_subtitle(player, FALSE);
3417 event = gst_event_new_seek(rate, format, flags, cur_type,
3418 cur, stop_type, stop);
3420 result = __mmplayer_gst_send_event_to_sink(player, event);
3428 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3430 int ret = MM_ERROR_NONE;
3431 gint64 pos_nsec = 0;
3432 gboolean accurated = FALSE;
3433 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3436 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3437 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3439 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3440 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3443 ret = __mmplayer_gst_check_duration(player, position);
3444 if (ret != MM_ERROR_NONE) {
3445 LOGE("failed to check duration 0x%X", ret);
3446 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3449 if (!__mmplayer_gst_check_seekable(player))
3450 return MM_ERROR_PLAYER_NO_OP;
3452 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3453 position, player->playback_rate, player->duration);
3455 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3456 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3457 This causes problem is position calculation during normal pause resume scenarios also.
3458 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3459 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3460 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3461 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3462 LOGW("getting current position failed in seek");
3464 player->last_position = pos_nsec;
3465 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3468 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3469 LOGD("not completed seek");
3470 return MM_ERROR_PLAYER_DOING_SEEK;
3473 if (!internal_called)
3474 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3476 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3477 that's why set position through property. */
3478 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3479 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3480 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3481 (!player->videodec_linked) && (!player->audiodec_linked)) {
3483 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3484 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3486 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3487 player->seek_state = MMPLAYER_SEEK_NONE;
3488 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3490 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3492 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3494 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3496 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3497 GST_FORMAT_TIME, seek_flags,
3498 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3499 LOGE("failed to set position");
3504 /* NOTE : store last seeking point to overcome some bad operation
3505 * (returning zero when getting current position) of some elements
3507 player->last_position = position;
3509 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3510 if (player->playback_rate > 1.0)
3511 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3513 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3514 LOGD("buffering should be reset after seeking");
3515 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3516 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3520 return MM_ERROR_NONE;
3523 player->pending_seek.is_pending = TRUE;
3524 player->pending_seek.pos = position;
3526 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3527 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3528 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3529 player->pending_seek.pos);
3531 return MM_ERROR_NONE;
3534 player->seek_state = MMPLAYER_SEEK_NONE;
3535 return MM_ERROR_PLAYER_SEEK;
3539 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3541 #define TRICKPLAY_OFFSET GST_MSECOND
3543 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3544 gint64 pos_nsec = 0;
3545 gboolean ret = TRUE;
3547 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3548 MM_ERROR_PLAYER_NOT_INITIALIZED);
3550 current_state = MMPLAYER_CURRENT_STATE(player);
3552 /* NOTE : query position except paused state to overcome some bad operation
3553 * please refer to below comments in details
3555 if (current_state != MM_PLAYER_STATE_PAUSED)
3556 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3558 /* NOTE : get last point to overcome some bad operation of some elements
3559 *(returning zero when getting current position in paused state
3560 * and when failed to get postion during seeking
3562 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3563 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3565 if (player->playback_rate < 0.0)
3566 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3568 pos_nsec = player->last_position;
3571 pos_nsec = player->last_position;
3573 player->last_position = pos_nsec;
3575 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3578 if (player->duration > 0 && pos_nsec > player->duration)
3579 pos_nsec = player->duration;
3581 player->last_position = pos_nsec;
3584 *position = pos_nsec;
3586 return MM_ERROR_NONE;
3589 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3591 #define STREAMING_IS_FINISHED 0
3592 #define BUFFERING_MAX_PER 100
3593 #define DEFAULT_PER_VALUE -1
3594 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3596 MMPlayerGstElement *mainbin = NULL;
3597 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3598 gint64 buffered_total = 0;
3599 gint64 position = 0;
3600 gint buffered_sec = -1;
3601 GstBufferingMode mode = GST_BUFFERING_STREAM;
3602 gint64 content_size_time = player->duration;
3603 guint64 content_size_bytes = player->http_content_size;
3605 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3607 player->pipeline->mainbin,
3608 MM_ERROR_PLAYER_NOT_INITIALIZED);
3610 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3615 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3616 /* and rtsp is not ready yet. */
3617 LOGW("it's only used for http streaming case");
3618 return MM_ERROR_PLAYER_NO_OP;
3621 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3622 LOGW("Time format is not supported yet");
3623 return MM_ERROR_INVALID_ARGUMENT;
3626 if (content_size_time <= 0 || content_size_bytes <= 0) {
3627 LOGW("there is no content size");
3628 return MM_ERROR_NONE;
3631 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3632 LOGW("fail to get current position");
3633 return MM_ERROR_NONE;
3636 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3637 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3639 mainbin = player->pipeline->mainbin;
3640 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3642 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3643 GstQuery *query = NULL;
3644 gint byte_in_rate = 0, byte_out_rate = 0;
3645 gint64 estimated_total = 0;
3647 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3648 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3649 LOGW("fail to get buffering query from queue2");
3651 gst_query_unref(query);
3652 return MM_ERROR_NONE;
3655 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3656 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3658 if (mode == GST_BUFFERING_STREAM) {
3659 /* using only queue in case of push mode(ts / mp3) */
3660 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3661 GST_FORMAT_BYTES, &buffered_total)) {
3662 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3663 stop_per = 100 * buffered_total / content_size_bytes;
3666 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3668 guint num_of_ranges = 0;
3669 gint64 start_byte = 0, stop_byte = 0;
3671 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3672 if (estimated_total != STREAMING_IS_FINISHED) {
3673 /* buffered size info from queue2 */
3674 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3675 for (idx = 0; idx < num_of_ranges; idx++) {
3676 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3677 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3679 buffered_total += (stop_byte - start_byte);
3682 stop_per = BUFFERING_MAX_PER;
3684 gst_query_unref(query);
3687 if (stop_per == DEFAULT_PER_VALUE) {
3688 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3690 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3692 /* buffered size info from multiqueue */
3693 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3694 guint curr_size_bytes = 0;
3695 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3696 "curr-size-bytes", &curr_size_bytes, NULL);
3697 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3698 buffered_total += curr_size_bytes;
3701 if (avg_byterate > 0)
3702 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3703 else if (player->total_maximum_bitrate > 0)
3704 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3705 else if (player->total_bitrate > 0)
3706 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3708 if (buffered_sec >= 0)
3709 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3713 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3714 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3716 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3717 buffered_total, buffered_sec, *start_pos, *stop_pos);
3719 return MM_ERROR_NONE;
3722 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3724 GstElement* element = NULL;
3727 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3728 player->pipeline->mainbin, NULL);
3730 /* setup source for gapless play */
3731 switch (player->profile.uri_type) {
3733 case MM_PLAYER_URI_TYPE_FILE:
3734 element = __mmplayer_gst_make_file_src(player);
3736 case MM_PLAYER_URI_TYPE_URL_HTTP:
3737 element = __mmplayer_gst_make_http_src(player);
3740 LOGE("not support uri type %d", player->profile.uri_type);
3745 LOGE("failed to create source element");
3753 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3755 MMHandleType attrs = 0;
3758 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3759 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3761 /* get profile attribute */
3762 attrs = MMPLAYER_GET_ATTRS(player);
3764 LOGE("failed to get content attribute");
3765 return MM_ERROR_PLAYER_INTERNAL;
3768 SECURE_LOGD("uri : %s", player->profile.uri);
3770 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3771 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3772 LOGE("failed to commit");
3774 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3775 return MM_ERROR_PLAYER_INTERNAL;
3777 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3778 return MM_ERROR_PLAYER_INTERNAL;
3780 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3781 return MM_ERROR_PLAYER_INTERNAL;
3784 return MM_ERROR_NONE;
3787 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3789 MMPlayerGstElement *mainbin = NULL;
3790 GstElement *pd_src = NULL;
3791 GstElement *pd_queue = NULL;
3792 GstElement *pd_decodebin = NULL;
3793 GList* element_bucket = NULL;
3794 MMHandleType attrs = 0;
3796 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3800 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3802 /* get profile attribute */
3803 attrs = MMPLAYER_GET_ATTRS(player);
3805 LOGE("failed to get content attribute");
3806 return MM_ERROR_PLAYER_INTERNAL;
3809 LOGD("http playback with progressive download : %d", player->pd_mode);
3811 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3812 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3813 MMPLAYER_FREEIF(player->pd_file_save_path);
3815 SECURE_LOGD("PD Location : %s", path);
3817 LOGE("filed to find pd location");
3818 return MM_ERROR_PLAYER_INTERNAL;
3821 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3822 LOGE("failed to get storage info");
3823 return MM_ERROR_PLAYER_INTERNAL;
3825 player->pd_file_save_path = g_strdup(path);
3828 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3830 LOGE("failed to create PD push source");
3831 return MM_ERROR_PLAYER_INTERNAL;
3834 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3835 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3837 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3839 mainbin = player->pipeline->mainbin;
3841 /* take source element */
3842 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3843 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3844 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3847 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3848 pd_queue = gst_element_factory_make("queue2", "queue2");
3850 LOGE("failed to create pd buffer element");
3855 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3856 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3857 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3859 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3861 player->streamer->is_pd_mode = TRUE;
3863 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3864 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3865 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3867 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3868 if (!pd_decodebin) {
3869 LOGE("failed to create decodebin");
3873 /* default size of mq in decodebin is 2M
3874 * but it can cause blocking issue during seeking depends on content. */
3875 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3877 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3878 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3880 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3882 /* add elements to pipeline */
3883 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3884 LOGE("failed to add elements to pipeline");
3888 /* linking elements in the bucket by added order. */
3889 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3890 LOGE("failed to link some elements");
3894 g_list_free(element_bucket);
3897 return MM_ERROR_NONE;
3900 MMPLAYER_FREEIF(player->pd_file_save_path);
3901 g_list_free(element_bucket);
3903 if (mainbin[MMPLAYER_M_SRC].gst)
3904 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3906 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3907 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3909 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3910 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3912 mainbin[MMPLAYER_M_SRC].gst = NULL;
3913 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3914 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3916 return MM_ERROR_PLAYER_INTERNAL;
3919 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3921 MMPlayerGstElement *mainbin = NULL;
3922 GstElement* src_elem = NULL;
3923 GstElement *autoplug_elem = NULL;
3924 GList* element_bucket = NULL;
3925 MMHandleType attrs = 0;
3926 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3929 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3930 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3932 /* get profile attribute */
3933 attrs = MMPLAYER_GET_ATTRS(player);
3935 LOGE("failed to get content attribute");
3936 return MM_ERROR_PLAYER_INTERNAL;
3939 LOGD("uri type %d", player->profile.uri_type);
3941 /* create source element */
3942 switch (player->profile.uri_type) {
3943 case MM_PLAYER_URI_TYPE_URL_RTSP:
3944 src_elem = __mmplayer_gst_make_rtsp_src(player);
3946 case MM_PLAYER_URI_TYPE_URL_HTTP:
3947 src_elem = __mmplayer_gst_make_http_src(player);
3949 case MM_PLAYER_URI_TYPE_FILE:
3950 src_elem = __mmplayer_gst_make_file_src(player);
3952 case MM_PLAYER_URI_TYPE_SS:
3954 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3955 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3957 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3961 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3962 LOGD("get timeout from ini");
3963 http_timeout = player->ini.http_timeout;
3966 /* setting property to streaming source */
3967 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3970 case MM_PLAYER_URI_TYPE_MEM:
3972 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3974 src_elem = gst_element_factory_make("appsrc", "mem-source");
3976 LOGE("failed to create appsrc element");
3980 g_object_set(src_elem, "stream-type", stream_type,
3981 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3983 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3984 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3985 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3986 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3990 LOGE("not support uri type");
3995 LOGE("failed to create source element");
3996 return MM_ERROR_PLAYER_INTERNAL;
3999 mainbin = player->pipeline->mainbin;
4001 /* take source element */
4002 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4004 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4005 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4006 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4008 /* create next element for auto-plugging */
4009 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4010 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4011 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4012 if (!autoplug_elem) {
4013 LOGE("failed to create typefind element");
4017 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4018 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4019 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4020 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4021 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4022 if (!autoplug_elem) {
4023 LOGE("failed to create decodebin");
4027 /* default size of mq in decodebin is 2M
4028 * but it can cause blocking issue during seeking depends on content. */
4029 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4032 if (autoplug_elem) {
4033 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4034 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4035 mainbin[autoplug_elem_id].gst = autoplug_elem;
4037 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4040 /* add elements to pipeline */
4041 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4042 LOGE("failed to add elements to pipeline");
4046 /* linking elements in the bucket by added order. */
4047 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4048 LOGE("failed to link some elements");
4052 /* FIXME: need to check whether this is required or not. */
4053 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4054 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4055 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4056 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4058 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4059 LOGE("failed to create fakesink");
4062 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4064 /* take ownership of fakesink. we are reusing it */
4065 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4067 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4068 LOGE("failed to add fakesink to bin");
4069 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4074 g_list_free(element_bucket);
4077 return MM_ERROR_NONE;
4080 g_list_free(element_bucket);
4082 if (mainbin[MMPLAYER_M_SRC].gst)
4083 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4085 if (mainbin[autoplug_elem_id].gst)
4086 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4088 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4089 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4091 mainbin[MMPLAYER_M_SRC].gst = NULL;
4092 mainbin[autoplug_elem_id].gst = NULL;
4093 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4095 return MM_ERROR_PLAYER_INTERNAL;
4098 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4101 MMPlayerGstElement *mainbin = NULL;
4104 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4105 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4107 mainbin = player->pipeline->mainbin;
4109 /* connect bus callback */
4110 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4112 LOGE("cannot get bus from pipeline");
4113 return MM_ERROR_PLAYER_INTERNAL;
4116 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4117 player->context.thread_default = g_main_context_get_thread_default();
4118 if (player->context.thread_default == NULL) {
4119 player->context.thread_default = g_main_context_default();
4120 LOGD("thread-default context is the global default context");
4122 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4124 /* set sync handler to get tag synchronously */
4125 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4126 gst_object_unref(GST_OBJECT(bus));
4128 /* create gst bus_msb_cb thread */
4129 g_mutex_init(&player->bus_msg_thread_mutex);
4130 g_cond_init(&player->bus_msg_thread_cond);
4131 player->bus_msg_thread_exit = FALSE;
4132 player->bus_msg_thread =
4133 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4134 if (!player->bus_msg_thread) {
4135 LOGE("failed to create gst BUS msg thread");
4136 g_mutex_clear(&player->bus_msg_thread_mutex);
4137 g_cond_clear(&player->bus_msg_thread_cond);
4138 return MM_ERROR_PLAYER_INTERNAL;
4142 return MM_ERROR_NONE;