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;
1042 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1043 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1049 __mmplayer_handle_buffering_playback(mm_player_t* player)
1051 int ret = MM_ERROR_NONE;
1052 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1053 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1054 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1055 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1057 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1058 LOGW("do nothing for buffering msg\n");
1059 ret = MM_ERROR_PLAYER_INVALID_STATE;
1063 prev_state = MMPLAYER_PREV_STATE(player);
1064 current_state = MMPLAYER_CURRENT_STATE(player);
1065 target_state = MMPLAYER_TARGET_STATE(player);
1066 pending_state = MMPLAYER_PENDING_STATE(player);
1068 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1069 MMPLAYER_STATE_GET_NAME(prev_state),
1070 MMPLAYER_STATE_GET_NAME(current_state),
1071 MMPLAYER_STATE_GET_NAME(pending_state),
1072 MMPLAYER_STATE_GET_NAME(target_state),
1073 player->streamer->buffering_state);
1075 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1076 /* NOTE : if buffering has done, player has to go to target state. */
1077 switch (target_state) {
1078 case MM_PLAYER_STATE_PAUSED:
1080 switch (pending_state) {
1081 case MM_PLAYER_STATE_PLAYING:
1082 __mmplayer_gst_pause(player, TRUE);
1085 case MM_PLAYER_STATE_PAUSED:
1086 LOGD("player is already going to paused state, there is nothing to do.\n");
1089 case MM_PLAYER_STATE_NONE:
1090 case MM_PLAYER_STATE_NULL:
1091 case MM_PLAYER_STATE_READY:
1093 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1099 case MM_PLAYER_STATE_PLAYING:
1101 switch (pending_state) {
1102 case MM_PLAYER_STATE_NONE:
1104 if (current_state != MM_PLAYER_STATE_PLAYING)
1105 __mmplayer_gst_resume(player, TRUE);
1109 case MM_PLAYER_STATE_PAUSED:
1110 /* NOTE: It should be worked as asynchronously.
1111 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1113 if (current_state == MM_PLAYER_STATE_PLAYING) {
1114 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1115 * The current state should be changed to paused purposely to prevent state conflict.
1117 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1119 __mmplayer_gst_resume(player, TRUE);
1122 case MM_PLAYER_STATE_PLAYING:
1123 LOGD("player is already going to playing state, there is nothing to do.\n");
1126 case MM_PLAYER_STATE_NULL:
1127 case MM_PLAYER_STATE_READY:
1129 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1135 case MM_PLAYER_STATE_NULL:
1136 case MM_PLAYER_STATE_READY:
1137 case MM_PLAYER_STATE_NONE:
1139 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1143 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1144 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1146 switch (pending_state) {
1147 case MM_PLAYER_STATE_NONE:
1149 if (current_state != MM_PLAYER_STATE_PAUSED) {
1150 /* rtsp streaming pause makes rtsp server stop sending data. */
1151 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1152 LOGD("set pause state during buffering\n");
1153 __mmplayer_gst_pause(player, TRUE);
1159 case MM_PLAYER_STATE_PLAYING:
1160 /* rtsp streaming pause makes rtsp server stop sending data. */
1161 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1162 __mmplayer_gst_pause(player, TRUE);
1165 case MM_PLAYER_STATE_PAUSED:
1168 case MM_PLAYER_STATE_NULL:
1169 case MM_PLAYER_STATE_READY:
1171 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1180 static VariantData *
1181 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1183 VariantData *var_info = NULL;
1184 g_return_val_if_fail(self != NULL, NULL);
1186 var_info = g_new0(VariantData, 1);
1187 if (!var_info) return NULL;
1188 var_info->bandwidth = self->bandwidth;
1189 var_info->width = self->width;
1190 var_info->height = self->height;
1195 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1201 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1202 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1204 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1205 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1206 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1208 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1209 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1210 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1213 /* handling audio clip which has vbr. means duration is keep changing */
1214 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1223 __mmplayer_eos_timer_cb(gpointer u_data)
1225 mm_player_t* player = NULL;
1226 MMHandleType attrs = 0;
1229 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1231 player = (mm_player_t*) u_data;
1232 attrs = MMPLAYER_GET_ATTRS(player);
1234 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1238 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1239 if (ret_value != MM_ERROR_NONE)
1240 LOGE("seeking to 0 failed in repeat play");
1243 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1246 /* we are returning FALSE as we need only one posting */
1251 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1253 MMPLAYER_RETURN_IF_FAIL(player);
1255 /* post now if delay is zero */
1256 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
1257 LOGD("eos delay is zero. posting EOS now\n");
1258 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1260 if (player->set_mode.pcm_extraction)
1261 __mmplayer_cancel_eos_timer(player);
1266 /* cancel if existing */
1267 __mmplayer_cancel_eos_timer(player);
1269 /* init new timeout */
1270 /* NOTE : consider give high priority to this timer */
1271 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1273 player->eos_timer = g_timeout_add(delay_in_ms,
1274 __mmplayer_eos_timer_cb, player);
1276 player->context.global_default = g_main_context_default();
1277 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1279 /* check timer is valid. if not, send EOS now */
1280 if (player->eos_timer == 0) {
1281 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1282 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1286 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1288 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1289 int ret = MM_ERROR_NONE;
1293 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1295 if (!player->pending_seek.is_pending) {
1296 LOGD("pending seek is not reserved. nothing to do.\n");
1300 /* check player state if player could pending seek or not. */
1301 current_state = MMPLAYER_CURRENT_STATE(player);
1303 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1304 LOGW("try to pending seek in %s state, try next time. \n",
1305 MMPLAYER_STATE_GET_NAME(current_state));
1309 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1311 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1313 if (MM_ERROR_NONE != ret)
1314 LOGE("failed to seek pending postion. just keep staying current position.\n");
1316 player->pending_seek.is_pending = FALSE;
1324 __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1326 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1328 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1330 audiobin = player->pipeline->audiobin; /* can be null */
1331 videobin = player->pipeline->videobin; /* can be null */
1332 textbin = player->pipeline->textbin; /* can be null */
1334 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1336 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1337 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1339 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1340 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1342 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1343 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1349 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1351 MMPlayerGstElement *textbin;
1354 MMPLAYER_RETURN_IF_FAIL(player &&
1356 player->pipeline->textbin);
1358 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1360 textbin = player->pipeline->textbin;
1363 LOGD("Drop subtitle text after getting EOS\n");
1365 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
1366 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1368 player->is_subtitle_force_drop = TRUE;
1370 if (player->is_subtitle_force_drop == TRUE) {
1371 LOGD("Enable subtitle data path without drop\n");
1373 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1374 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
1376 LOGD("non-connected with external display");
1378 player->is_subtitle_force_drop = FALSE;
1384 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1386 MMHandleType attrs = 0;
1391 /* NOTE : EOS event is comming multiple time. watch out it */
1392 /* check state. we only process EOS when pipeline state goes to PLAYING */
1393 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1394 LOGD("EOS received on non-playing state. ignoring it");
1398 if (player->pipeline) {
1399 if (player->pipeline->textbin)
1400 __mmplayer_drop_subtitle(player, TRUE);
1402 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1405 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1407 LOGD("release audio callback");
1409 /* release audio callback */
1410 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1411 player->audio_cb_probe_id = 0;
1412 /* audio callback should be free because it can be called even though probe remove.*/
1413 player->audio_stream_cb = NULL;
1414 player->audio_stream_cb_user_param = NULL;
1418 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1419 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1421 /* rewind if repeat count is greater then zero */
1422 /* get play count */
1423 attrs = MMPLAYER_GET_ATTRS(player);
1426 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1428 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1430 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1431 if (player->playback_rate < 0.0) {
1432 player->resumed_by_rewind = TRUE;
1433 _mmplayer_set_mute((MMHandleType)player, 0);
1434 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1437 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1440 player->sent_bos = FALSE;
1442 LOGD("do not post eos msg for repeating");
1447 if (player->pipeline)
1448 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1450 /* post eos message to application */
1451 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1453 /* reset last position */
1454 player->last_position = 0;
1461 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1463 GError *error = NULL;
1464 gchar* debug = NULL;
1468 /* generating debug info before returning error */
1469 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1471 /* get error code */
1472 gst_message_parse_error(msg, &error, &debug);
1474 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1475 /* Note : the streaming error from the streaming source is handled
1476 * using __mmplayer_handle_streaming_error.
1478 __mmplayer_handle_streaming_error(player, msg);
1480 /* dump state of all element */
1481 __mmplayer_dump_pipeline_state(player);
1483 /* traslate gst error code to msl error code. then post it
1484 * to application if needed
1486 __mmplayer_handle_gst_error(player, msg, error);
1489 LOGE("error debug : %s", debug);
1492 if (MMPLAYER_IS_HTTP_PD(player))
1493 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1495 MMPLAYER_FREEIF(debug);
1496 g_error_free(error);
1503 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1505 MMMessageParamType msg_param = {0, };
1506 int bRet = MM_ERROR_NONE;
1509 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1511 if (!MMPLAYER_IS_STREAMING(player)) {
1512 LOGW("this is not streaming playback.");
1516 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1517 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1518 /* skip the playback control by buffering msg while user request is handled. */
1521 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1523 gst_message_parse_buffering(msg, &per);
1524 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1526 msg_param.connection.buffering = per;
1527 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1531 MMPLAYER_CMD_LOCK(player);
1534 if (!player->streamer) {
1535 LOGW("Pipeline is shutting down");
1536 MMPLAYER_CMD_UNLOCK(player);
1540 /* ignore the remained buffering message till getting 100% msg */
1541 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1542 gint buffer_percent = 0;
1544 gst_message_parse_buffering(msg, &buffer_percent);
1546 if (buffer_percent == MAX_BUFFER_PERCENT) {
1547 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1548 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1550 MMPLAYER_CMD_UNLOCK(player);
1554 /* ignore the remained buffering message */
1555 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1556 gint buffer_percent = 0;
1558 gst_message_parse_buffering(msg, &buffer_percent);
1560 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1561 player->streamer->buffering_percent, buffer_percent);
1563 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1564 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1565 player->streamer->buffering_req.is_pre_buffering = FALSE;
1567 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1569 LOGD("interrupted buffering - ignored the remained buffering msg!");
1570 MMPLAYER_CMD_UNLOCK(player);
1575 __mmplayer_update_buffer_setting(player, msg);
1577 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1579 if (bRet == MM_ERROR_NONE) {
1580 msg_param.connection.buffering = player->streamer->buffering_percent;
1581 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1583 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1584 player->pending_resume &&
1585 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1587 player->is_external_subtitle_added_now = FALSE;
1588 player->pending_resume = FALSE;
1589 _mmplayer_resume((MMHandleType)player);
1592 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1593 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1595 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1596 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1597 player->seek_state = MMPLAYER_SEEK_NONE;
1598 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1599 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1600 /* Considering the async state trasition in case of RTSP.
1601 After getting state change gst msg, seek cmpleted msg will be posted. */
1602 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1606 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1607 if (!player->streamer) {
1608 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1609 MMPLAYER_CMD_UNLOCK(player);
1613 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1615 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1616 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1618 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1619 msg_param.connection.buffering = player->streamer->buffering_percent;
1620 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1622 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1625 msg_param.connection.buffering = player->streamer->buffering_percent;
1626 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1629 MMPLAYER_CMD_UNLOCK(player);
1637 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1639 MMPlayerGstElement *mainbin;
1640 const GValue *voldstate, *vnewstate, *vpending;
1641 GstState oldstate = GST_STATE_NULL;
1642 GstState newstate = GST_STATE_NULL;
1643 GstState pending = GST_STATE_NULL;
1646 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1648 mainbin = player->pipeline->mainbin;
1650 /* we only handle messages from pipeline */
1651 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1654 /* get state info from msg */
1655 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1656 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1657 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1659 if (!voldstate || !vnewstate) {
1660 LOGE("received msg has wrong format.");
1664 oldstate = (GstState)voldstate->data[0].v_int;
1665 newstate = (GstState)vnewstate->data[0].v_int;
1667 pending = (GstState)vpending->data[0].v_int;
1669 LOGD("state changed [%s] : %s ---> %s final : %s",
1670 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1671 gst_element_state_get_name((GstState)oldstate),
1672 gst_element_state_get_name((GstState)newstate),
1673 gst_element_state_get_name((GstState)pending));
1675 if (newstate == GST_STATE_PLAYING) {
1676 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1678 int retVal = MM_ERROR_NONE;
1679 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1681 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1683 if (MM_ERROR_NONE != retVal)
1684 LOGE("failed to seek pending postion. just keep staying current position.");
1686 player->pending_seek.is_pending = FALSE;
1690 if (oldstate == newstate) {
1691 LOGD("pipeline reports state transition to old state");
1696 case GST_STATE_PAUSED:
1698 gboolean prepare_async = FALSE;
1700 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1701 __mmplayer_configure_audio_callback(player);
1703 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1704 // managed prepare async case
1705 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1706 LOGD("checking prepare mode for async transition - %d", prepare_async);
1709 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1710 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1712 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1713 __mm_player_streaming_set_content_bitrate(player->streamer,
1714 player->total_maximum_bitrate, player->total_bitrate);
1716 if (player->pending_seek.is_pending) {
1717 LOGW("trying to do pending seek");
1718 MMPLAYER_CMD_LOCK(player);
1719 __mmplayer_gst_pending_seek(player);
1720 MMPLAYER_CMD_UNLOCK(player);
1726 case GST_STATE_PLAYING:
1728 if (MMPLAYER_IS_STREAMING(player)) {
1729 // managed prepare async case when buffering is completed
1730 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1731 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1732 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1733 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1735 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1737 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1738 if (player->streamer->buffering_percent < 100) {
1740 MMMessageParamType msg_param = {0, };
1741 LOGW("Posting Buffering Completed Message to Application !!!");
1743 msg_param.connection.buffering = 100;
1744 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1749 if (player->gapless.stream_changed) {
1750 __mmplayer_update_content_attrs(player, ATTR_ALL);
1751 player->gapless.stream_changed = FALSE;
1754 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1755 player->seek_state = MMPLAYER_SEEK_NONE;
1756 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1760 case GST_STATE_VOID_PENDING:
1761 case GST_STATE_NULL:
1762 case GST_STATE_READY:
1772 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1774 const gchar *structure_name;
1775 gint count = 0, idx = 0;
1776 MMHandleType attrs = 0;
1779 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1781 attrs = MMPLAYER_GET_ATTRS(player);
1783 LOGE("Failed to get content attribute");
1787 if (gst_message_get_structure(msg) == NULL)
1790 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1791 if (!structure_name)
1794 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1796 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1797 const GValue *var_info = NULL;
1799 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1800 if (var_info != NULL) {
1801 if (player->adaptive_info.var_list)
1802 g_list_free_full(player->adaptive_info.var_list, g_free);
1804 /* share addr or copy the list */
1805 player->adaptive_info.var_list =
1806 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1808 count = g_list_length(player->adaptive_info.var_list);
1810 VariantData *temp = NULL;
1812 /* print out for debug */
1813 LOGD("num of variant_info %d", count);
1814 for (idx = 0; idx < count; idx++) {
1815 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1817 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1823 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1824 gint num_buffers = 0;
1825 gint extra_num_buffers = 0;
1827 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1828 player->video_num_buffers = num_buffers;
1829 LOGD("video_num_buffers : %d", player->video_num_buffers);
1832 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1833 player->video_extra_num_buffers = extra_num_buffers;
1834 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1839 if (!strcmp(structure_name, "Language_list")) {
1840 const GValue *lang_list = NULL;
1841 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1842 if (lang_list != NULL) {
1843 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1845 LOGD("Total audio tracks(from parser) = %d \n", count);
1849 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1850 const GValue *lang_list = NULL;
1851 MMPlayerLangStruct *temp = NULL;
1853 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1854 if (lang_list != NULL) {
1855 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1857 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1858 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1859 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1860 if (mmf_attrs_commit(attrs))
1861 LOGE("failed to commit.\n");
1862 LOGD("Total subtitle tracks = %d \n", count);
1865 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1867 LOGD("value of lang_key is %s and lang_code is %s",
1868 temp->language_key, temp->language_code);
1871 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1872 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1877 /* custom message */
1878 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1879 MMMessageParamType msg_param = {0,};
1880 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1881 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1884 /* custom message for RTSP attribute :
1885 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1886 sdp which has contents info is received when rtsp connection is opened.
1887 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1888 if (!strcmp(structure_name, "rtspsrc_properties")) {
1890 gchar *audio_codec = NULL;
1891 gchar *video_codec = NULL;
1892 gchar *video_frame_size = NULL;
1894 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1895 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1896 player->streaming_type = __mmplayer_get_stream_service_type(player);
1898 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1899 LOGD("rtsp_audio_codec : %s", audio_codec);
1901 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1903 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1904 LOGD("rtsp_video_codec : %s", video_codec);
1906 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1908 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1909 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1910 if (video_frame_size) {
1912 char *seperator = strchr(video_frame_size, '-');
1915 char video_width[10] = {0,};
1916 int frame_size_len = strlen(video_frame_size);
1917 int separtor_len = strlen(seperator);
1919 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1920 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1923 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1927 if (mmf_attrs_commit(attrs))
1928 LOGE("failed to commit.\n");
1936 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1938 MMPlayerGstElement *mainbin;
1941 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1943 mainbin = player->pipeline->mainbin;
1945 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1947 /* we only handle messages from pipeline */
1948 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1951 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1952 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1953 player->seek_state = MMPLAYER_SEEK_NONE;
1954 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1955 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1956 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1957 LOGD("sync %s state(%s) with parent state(%s)",
1958 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1959 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1960 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1962 /* In case of streaming, pause is required before finishing seeking by buffering.
1963 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1964 Because the buffering state is controlled according to the state transition for force resume,
1965 the decodebin state should be paused as player state. */
1966 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1969 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1970 (player->streamer) &&
1971 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1972 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1973 GstQuery *query = NULL;
1974 gboolean busy = FALSE;
1977 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1978 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1979 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1980 gst_query_parse_buffering_percent(query, &busy, &percent);
1981 gst_query_unref(query);
1983 LOGD("buffered percent(%s): %d\n",
1984 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1988 __mmplayer_handle_buffering_playback(player);
1991 player->seek_state = MMPLAYER_SEEK_COMPLETED;
2000 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
2002 mm_player_t* player = (mm_player_t*)(data);
2004 MMPLAYER_RETURN_IF_FAIL(player);
2005 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2007 switch (GST_MESSAGE_TYPE(msg)) {
2008 case GST_MESSAGE_UNKNOWN:
2009 LOGD("unknown message received\n");
2012 case GST_MESSAGE_EOS:
2013 LOGD("GST_MESSAGE_EOS received");
2014 __mmplayer_gst_handle_eos_message(player, msg);
2017 case GST_MESSAGE_ERROR:
2018 __mmplayer_gst_handle_error_message(player, msg);
2021 case GST_MESSAGE_WARNING:
2024 GError* error = NULL;
2026 gst_message_parse_warning(msg, &error, &debug);
2028 LOGD("warning : %s\n", error->message);
2029 LOGD("debug : %s\n", debug);
2031 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2033 MMPLAYER_FREEIF(debug);
2034 g_error_free(error);
2038 case GST_MESSAGE_TAG:
2040 LOGD("GST_MESSAGE_TAG\n");
2041 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2042 LOGW("failed to extract tags from gstmessage\n");
2046 case GST_MESSAGE_BUFFERING:
2047 __mmplayer_gst_handle_buffering_message(player, msg);
2050 case GST_MESSAGE_STATE_CHANGED:
2051 __mmplayer_gst_handle_state_message(player, msg);
2054 case GST_MESSAGE_CLOCK_LOST:
2056 GstClock *clock = NULL;
2057 gboolean need_new_clock = FALSE;
2059 gst_message_parse_clock_lost(msg, &clock);
2060 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2062 if (!player->videodec_linked)
2063 need_new_clock = TRUE;
2064 else if (!player->ini.use_system_clock)
2065 need_new_clock = TRUE;
2067 if (need_new_clock) {
2068 LOGD("Provide clock is TRUE, do pause->resume\n");
2069 __mmplayer_gst_pause(player, FALSE);
2070 __mmplayer_gst_resume(player, FALSE);
2075 case GST_MESSAGE_NEW_CLOCK:
2077 GstClock *clock = NULL;
2078 gst_message_parse_new_clock(msg, &clock);
2079 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2083 case GST_MESSAGE_ELEMENT:
2084 __mmplayer_gst_handle_element_message(player, msg);
2087 case GST_MESSAGE_DURATION_CHANGED:
2089 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2090 if (!__mmplayer_gst_handle_duration(player, msg))
2091 LOGW("failed to update duration");
2095 case GST_MESSAGE_ASYNC_START:
2096 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2099 case GST_MESSAGE_ASYNC_DONE:
2100 __mmplayer_gst_handle_async_done_message(player, msg);
2103 #if 0 /* delete unnecessary logs */
2104 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2105 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2106 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2107 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2108 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2109 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2110 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2111 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2112 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2113 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2114 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2115 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2116 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2117 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2118 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2125 /* should not call 'gst_message_unref(msg)' */
2129 static GstBusSyncReply
2130 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2132 mm_player_t *player = (mm_player_t *)data;
2133 GstBusSyncReply reply = GST_BUS_DROP;
2135 if (!(player->pipeline && player->pipeline->mainbin)) {
2136 LOGE("player pipeline handle is null");
2137 return GST_BUS_PASS;
2140 if (!__mmplayer_gst_check_useful_message(player, message)) {
2141 gst_message_unref(message);
2142 return GST_BUS_DROP;
2145 switch (GST_MESSAGE_TYPE(message)) {
2146 case GST_MESSAGE_STATE_CHANGED:
2147 /* post directly for fast launch */
2148 if (player->sync_handler) {
2149 __mmplayer_gst_bus_msg_callback(message, player);
2150 reply = GST_BUS_DROP;
2152 reply = GST_BUS_PASS;
2154 case GST_MESSAGE_TAG:
2155 __mmplayer_gst_extract_tag_from_msg(player, message);
2159 GstTagList *tags = NULL;
2161 gst_message_parse_tag(message, &tags);
2163 LOGE("TAGS received from element \"%s\".\n",
2164 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2166 gst_tag_list_foreach(tags, print_tag, NULL);
2167 gst_tag_list_free(tags);
2175 case GST_MESSAGE_DURATION_CHANGED:
2176 __mmplayer_gst_handle_duration(player, message);
2178 case GST_MESSAGE_ASYNC_DONE:
2179 /* NOTE:Don't call gst_callback directly
2180 * because previous frame can be showed even though this message is received for seek.
2183 reply = GST_BUS_PASS;
2187 if (reply == GST_BUS_DROP)
2188 gst_message_unref(message);
2194 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2196 GstElement *appsrc = element;
2197 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2198 GstBuffer *buffer = NULL;
2199 GstFlowReturn ret = GST_FLOW_OK;
2202 MMPLAYER_RETURN_IF_FAIL(element);
2203 MMPLAYER_RETURN_IF_FAIL(buf);
2205 buffer = gst_buffer_new();
2207 if (buf->offset < 0 || buf->len < 0) {
2208 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2212 if (buf->offset >= buf->len) {
2213 LOGD("call eos appsrc");
2214 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2218 if (buf->len - buf->offset < size)
2219 len = buf->len - buf->offset;
2221 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2222 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2223 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2225 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2226 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2232 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2234 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2236 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2238 buf->offset = (int)size;
2244 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2246 mm_player_t *player = (mm_player_t*)user_data;
2247 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2248 guint64 current_level_bytes = 0;
2250 MMPLAYER_RETURN_IF_FAIL(player);
2252 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2253 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2254 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2255 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2256 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2257 type = MM_PLAYER_STREAM_TYPE_TEXT;
2259 LOGE("can not enter here");
2263 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2265 LOGI("type: %d, level: %llu", type, current_level_bytes);
2267 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2268 if (player->media_stream_buffer_status_cb[type])
2269 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2270 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2274 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2276 mm_player_t *player = (mm_player_t*)user_data;
2277 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2278 guint64 current_level_bytes = 0;
2280 MMPLAYER_RETURN_IF_FAIL(player);
2282 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2283 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2284 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2285 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2286 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2287 type = MM_PLAYER_STREAM_TYPE_TEXT;
2289 LOGE("can not enter here");
2293 LOGI("type: %d, buffer is full", type);
2295 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2297 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2299 if (player->media_stream_buffer_status_cb[type])
2300 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2302 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2306 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2308 mm_player_t *player = (mm_player_t*)user_data;
2309 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2311 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2313 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2314 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2315 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2316 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2317 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2318 type = MM_PLAYER_STREAM_TYPE_TEXT;
2320 LOGE("can not enter here");
2324 LOGD("type: %d, pos: %llu", type, position);
2325 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2327 if (player->media_stream_seek_data_cb[type])
2328 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2329 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2335 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2337 #define MAX_LEN_NAME 20
2339 gboolean ret = FALSE;
2340 GstPad *sinkpad = NULL;
2341 gchar *prefix = NULL;
2342 gchar dec_name[MAX_LEN_NAME] = {0};
2343 enum MainElementID elem_id = MMPLAYER_M_NUM;
2345 MMPlayerGstElement *mainbin = NULL;
2346 GstElement *decodebin = NULL;
2347 GstCaps *dec_caps = NULL;
2351 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2353 player->pipeline->mainbin, FALSE);
2354 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2356 mainbin = player->pipeline->mainbin;
2358 case MM_PLAYER_STREAM_TYPE_AUDIO:
2360 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2362 case MM_PLAYER_STREAM_TYPE_VIDEO:
2364 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2367 LOGE("invalid type %d", type);
2371 if (mainbin[elem_id].gst) {
2372 LOGE("elem(%d) is already created", elem_id);
2376 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2378 /* create decodebin */
2379 decodebin = gst_element_factory_make("decodebin", dec_name);
2381 LOGE("failed to create %s", dec_name);
2385 mainbin[elem_id].id = elem_id;
2386 mainbin[elem_id].gst = decodebin;
2388 /* raw pad handling signal */
2389 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2390 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2392 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2393 before looking for any elements that can handle that stream.*/
2394 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2395 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2397 /* This signal is emitted when a element is added to the bin.*/
2398 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2399 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2401 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2402 LOGE("failed to add new decodebin");
2406 dec_caps = gst_pad_query_caps(srcpad, NULL);
2408 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2409 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2410 gst_caps_unref(dec_caps);
2413 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2415 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2416 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2419 gst_object_unref(GST_OBJECT(sinkpad));
2421 gst_element_sync_state_with_parent(decodebin);
2427 gst_object_unref(GST_OBJECT(sinkpad));
2429 if (mainbin[elem_id].gst) {
2430 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2431 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2432 gst_object_unref(mainbin[elem_id].gst);
2433 mainbin[elem_id].gst = NULL;
2441 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2443 #define MAX_LEN_NAME 20
2444 MMPlayerGstElement *mainbin = NULL;
2445 gchar *prefix = NULL;
2446 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2448 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2449 GstElement *src = NULL, *queue = NULL;
2450 GstPad *srcpad = NULL;
2453 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2454 player->pipeline->mainbin, FALSE);
2456 mainbin = player->pipeline->mainbin;
2458 LOGD("type(%d) path is creating", type);
2460 case MM_PLAYER_STREAM_TYPE_AUDIO:
2462 if (mainbin[MMPLAYER_M_SRC].gst)
2463 src_id = MMPLAYER_M_2ND_SRC;
2465 src_id = MMPLAYER_M_SRC;
2466 queue_id = MMPLAYER_M_A_BUFFER;
2468 case MM_PLAYER_STREAM_TYPE_VIDEO:
2470 src_id = MMPLAYER_M_SRC;
2471 queue_id = MMPLAYER_M_V_BUFFER;
2473 case MM_PLAYER_STREAM_TYPE_TEXT:
2474 prefix = "subtitle";
2475 src_id = MMPLAYER_M_SUBSRC;
2476 queue_id = MMPLAYER_M_S_BUFFER;
2479 LOGE("invalid type %d", type);
2483 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2484 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2487 src = gst_element_factory_make("appsrc", src_name);
2489 LOGF("failed to create %s", src_name);
2493 mainbin[src_id].id = src_id;
2494 mainbin[src_id].gst = src;
2496 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2497 "caps", caps, NULL);
2499 /* size of many video frames are larger than default blocksize as 4096 */
2500 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2501 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2503 if (player->media_stream_buffer_max_size[type] > 0)
2504 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2506 if (player->media_stream_buffer_min_percent[type] > 0)
2507 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2509 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2510 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2512 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2513 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2514 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2515 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2516 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2517 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2520 queue = gst_element_factory_make("queue2", queue_name);
2522 LOGE("failed to create %s", queue_name);
2525 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2527 mainbin[queue_id].id = queue_id;
2528 mainbin[queue_id].gst = queue;
2530 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2531 LOGE("failed to add src");
2535 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2536 LOGE("failed to add queue");
2540 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2541 LOGE("failed to link src and queue");
2545 /* create decoder */
2546 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2548 LOGE("failed to get srcpad of queue");
2552 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2553 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2555 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2556 LOGE("failed to create decoder");
2557 gst_object_unref(GST_OBJECT(srcpad));
2561 gst_object_unref(GST_OBJECT(srcpad));
2565 if (mainbin[src_id].gst) {
2566 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2567 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2568 gst_object_unref(mainbin[src_id].gst);
2569 mainbin[src_id].gst = NULL;
2572 if (mainbin[queue_id].gst) {
2573 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2574 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2575 gst_object_unref(mainbin[queue_id].gst);
2576 mainbin[queue_id].gst = NULL;
2583 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2585 GstPad *sinkpad = NULL;
2586 GstCaps* caps = NULL;
2587 GstElement* new_element = NULL;
2588 GstStructure* str = NULL;
2589 const gchar* name = NULL;
2591 mm_player_t* player = (mm_player_t*) data;
2595 MMPLAYER_RETURN_IF_FAIL(element && pad);
2596 MMPLAYER_RETURN_IF_FAIL(player &&
2598 player->pipeline->mainbin);
2601 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2602 * num_dynamic_pad will decreased after creating a sinkbin.
2604 player->num_dynamic_pad++;
2605 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2607 caps = gst_pad_query_caps(pad, NULL);
2609 MMPLAYER_CHECK_NULL(caps);
2611 /* clear previous result*/
2612 player->have_dynamic_pad = FALSE;
2614 str = gst_caps_get_structure(caps, 0);
2617 LOGE("cannot get structure from caps.\n");
2621 name = gst_structure_get_name(str);
2623 LOGE("cannot get mimetype from structure.\n");
2627 if (strstr(name, "video")) {
2629 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2631 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2632 if (player->v_stream_caps) {
2633 gst_caps_unref(player->v_stream_caps);
2634 player->v_stream_caps = NULL;
2637 new_element = gst_element_factory_make("fakesink", NULL);
2638 player->num_dynamic_pad--;
2643 /* clear previous result*/
2644 player->have_dynamic_pad = FALSE;
2646 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2647 LOGE("failed to autoplug for caps");
2651 /* check if there's dynamic pad*/
2652 if (player->have_dynamic_pad) {
2653 LOGE("using pad caps assums there's no dynamic pad !\n");
2657 gst_caps_unref(caps);
2662 /* excute new_element if created*/
2664 LOGD("adding new element to pipeline\n");
2666 /* set state to READY before add to bin */
2667 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2669 /* add new element to the pipeline */
2670 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2671 LOGE("failed to add autoplug element to bin\n");
2675 /* get pad from element */
2676 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2678 LOGE("failed to get sinkpad from autoplug element\n");
2683 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2684 LOGE("failed to link autoplug element\n");
2688 gst_object_unref(sinkpad);
2691 /* run. setting PLAYING here since streamming source is live source */
2692 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2696 gst_caps_unref(caps);
2702 STATE_CHANGE_FAILED:
2704 /* FIXIT : take care if new_element has already added to pipeline */
2706 gst_object_unref(GST_OBJECT(new_element));
2709 gst_object_unref(GST_OBJECT(sinkpad));
2712 gst_caps_unref(caps);
2714 /* FIXIT : how to inform this error to MSL ????? */
2715 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2716 * then post an error to application
2721 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2723 mm_player_t* player = (mm_player_t*) data;
2727 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2728 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2729 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2730 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2732 * [1] audio and video will be dumped with filesink.
2733 * [2] autoplugging is done by just using pad caps.
2734 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2735 * and the video will be dumped via filesink.
2737 if (player->num_dynamic_pad == 0) {
2738 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2740 if (!__mmplayer_gst_remove_fakesink(player,
2741 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2742 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2743 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2744 * source element are not same. To overcome this situation, this function will called
2745 * several places and several times. Therefore, this is not an error case.
2750 /* create dot before error-return. for debugging */
2751 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2753 player->no_more_pad = TRUE;
2759 __mmplayer_gst_create_rtsp_src(mm_player_t* player)
2761 GstElement* element = NULL;
2762 gchar *user_agent = NULL;
2763 MMHandleType attrs = 0;
2766 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2768 /* get profile attribute */
2769 attrs = MMPLAYER_GET_ATTRS(player);
2771 LOGE("failed to get content attribute");
2775 element = gst_element_factory_make("rtspsrc", "rtsp source");
2777 LOGE("failed to create rtspsrc element");
2782 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2784 SECURE_LOGD("user_agent : %s", user_agent);
2786 /* setting property to streaming source */
2787 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2789 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2791 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2792 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2793 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2794 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2801 __mmplayer_gst_create_http_src(mm_player_t* player)
2803 GstElement* element = NULL;
2804 MMHandleType attrs = 0;
2805 gchar *user_agent, *cookies, **cookie_list;
2806 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2807 user_agent = cookies = NULL;
2811 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2813 /* get profile attribute */
2814 attrs = MMPLAYER_GET_ATTRS(player);
2816 LOGE("failed to get content attribute");
2820 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2822 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2824 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2829 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2830 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2832 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2833 http_timeout = player->ini.http_timeout;
2836 SECURE_LOGD("location : %s", player->profile.uri);
2837 SECURE_LOGD("cookies : %s", cookies);
2838 SECURE_LOGD("user_agent : %s", user_agent);
2839 LOGD("timeout : %d", http_timeout);
2841 /* setting property to streaming source */
2842 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2843 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2845 /* parsing cookies */
2846 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2847 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2848 g_strfreev(cookie_list);
2852 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2854 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2855 LOGW("[DASH] this is still experimental feature");
2862 __mmplayer_gst_create_file_src(mm_player_t* player)
2864 GstElement* element = NULL;
2867 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2869 LOGD("using filesrc for 'file://' handler");
2870 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2871 LOGE("failed to get storage info");
2875 element = gst_element_factory_make("filesrc", "source");
2877 LOGE("failed to create filesrc");
2881 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2887 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2889 mm_player_t *player = (mm_player_t *) data;
2891 g_return_val_if_fail(player, FALSE);
2892 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2894 gst_message_ref(msg);
2896 g_mutex_lock(&player->bus_msg_q_lock);
2897 g_queue_push_tail(player->bus_msg_q, msg);
2898 g_mutex_unlock(&player->bus_msg_q_lock);
2900 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2901 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2902 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2906 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2908 mm_player_t *player = (mm_player_t*)(data);
2909 GstMessage *msg = NULL;
2913 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2915 player->pipeline->mainbin &&
2916 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2919 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2921 LOGE("cannot get BUS from the pipeline");
2925 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2927 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2928 while (!player->bus_msg_thread_exit) {
2929 g_mutex_lock(&player->bus_msg_q_lock);
2930 msg = g_queue_pop_head(player->bus_msg_q);
2931 g_mutex_unlock(&player->bus_msg_q_lock);
2933 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2936 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2937 /* handle the gst msg */
2938 __mmplayer_gst_bus_msg_callback(msg, player);
2939 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2940 gst_message_unref(msg);
2943 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2944 gst_object_unref(GST_OBJECT(bus));
2951 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2953 gint64 dur_nsec = 0;
2956 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2958 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2959 return MM_ERROR_NONE;
2961 /* NOTE : duration cannot be zero except live streaming.
2962 * Since some element could have some timing problemn with quering duration, try again.
2964 if (player->duration == 0) {
2965 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2966 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2967 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2968 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2969 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2970 player->pending_seek.is_pending = TRUE;
2971 player->pending_seek.pos = position;
2972 player->seek_state = MMPLAYER_SEEK_NONE;
2973 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2974 return MM_ERROR_PLAYER_NO_OP;
2976 player->seek_state = MMPLAYER_SEEK_NONE;
2977 return MM_ERROR_PLAYER_SEEK;
2980 player->duration = dur_nsec;
2983 if (player->duration > 0 && player->duration < position) {
2984 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2985 return MM_ERROR_INVALID_ARGUMENT;
2989 return MM_ERROR_NONE;
2993 __mmplayer_gst_check_seekable(mm_player_t* player)
2995 GstQuery *query = NULL;
2996 gboolean seekable = FALSE;
2998 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3002 query = gst_query_new_seeking(GST_FORMAT_TIME);
3003 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3004 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3005 gst_query_unref(query);
3008 LOGW("non-seekable content");
3009 player->seek_state = MMPLAYER_SEEK_NONE;
3013 LOGW("failed to get seeking query");
3014 gst_query_unref(query); /* keep seeking operation */
3025 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
3027 GstState element_state = GST_STATE_VOID_PENDING;
3028 GstState element_pending_state = GST_STATE_VOID_PENDING;
3029 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3034 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3036 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3039 ret = gst_element_set_state(element, state);
3041 if (ret == GST_STATE_CHANGE_FAILURE) {
3042 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3044 /* dump state of all element */
3045 __mmplayer_dump_pipeline_state(player);
3047 return MM_ERROR_PLAYER_INTERNAL;
3050 /* return here so state transition to be done in async mode */
3052 LOGD("async state transition. not waiting for state complete.\n");
3053 return MM_ERROR_NONE;
3056 /* wait for state transition */
3057 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3059 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3060 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3061 GST_ELEMENT_NAME(element),
3062 gst_element_state_get_name(state), timeout);
3064 LOGE(" [%s] state : %s pending : %s \n",
3065 GST_ELEMENT_NAME(element),
3066 gst_element_state_get_name(element_state),
3067 gst_element_state_get_name(element_pending_state));
3069 /* dump state of all element */
3070 __mmplayer_dump_pipeline_state(player);
3072 return MM_ERROR_PLAYER_INTERNAL;
3075 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3079 return MM_ERROR_NONE;
3082 int __mmplayer_gst_start(mm_player_t* player)
3084 int ret = MM_ERROR_NONE;
3085 gboolean async = FALSE;
3089 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3091 /* NOTE : if SetPosition was called before Start. do it now */
3092 /* streaming doesn't support it. so it should be always sync */
3093 /* !!create one more api to check if there is pending seek rather than checking variables */
3094 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3095 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3096 ret = __mmplayer_gst_pause(player, FALSE);
3097 if (ret != MM_ERROR_NONE) {
3098 LOGE("failed to set state to PAUSED for pending seek");
3102 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3103 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3104 LOGW("failed to seek pending postion. starting from the begin of content");
3107 LOGD("current state before doing transition");
3108 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3109 MMPLAYER_PRINT_STATE(player);
3111 /* set pipeline state to PLAYING */
3112 ret = __mmplayer_gst_set_state(player,
3113 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3115 if (ret == MM_ERROR_NONE) {
3116 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3118 LOGE("failed to set state to PLAYING");
3122 /* generating debug info before returning error */
3123 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3130 int __mmplayer_gst_stop(mm_player_t* player)
3132 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3133 MMHandleType attrs = 0;
3134 gboolean rewind = FALSE;
3136 int ret = MM_ERROR_NONE;
3140 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3141 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3143 LOGD("current state before doing transition");
3144 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3145 MMPLAYER_PRINT_STATE(player);
3147 attrs = MMPLAYER_GET_ATTRS(player);
3149 LOGE("cannot get content attribute\n");
3150 return MM_ERROR_PLAYER_INTERNAL;
3153 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3154 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3156 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3157 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3160 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3161 /* disable the async state transition because there could be no data in the pipeline */
3162 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
3166 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3168 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3169 /* enable the async state transition as default operation */
3170 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
3173 /* return if set_state has failed */
3174 if (ret != MM_ERROR_NONE) {
3175 LOGE("failed to set state.\n");
3181 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3182 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3183 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3184 LOGW("failed to rewind\n");
3185 ret = MM_ERROR_PLAYER_SEEK;
3190 player->sent_bos = FALSE;
3192 if (player->es_player_push_mode) //for cloudgame
3195 /* wait for seek to complete */
3196 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3197 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3198 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3200 LOGE("fail to stop player.\n");
3201 ret = MM_ERROR_PLAYER_INTERNAL;
3202 __mmplayer_dump_pipeline_state(player);
3205 /* generate dot file if enabled */
3206 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3213 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3215 int ret = MM_ERROR_NONE;
3219 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3220 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3222 LOGD("current state before doing transition");
3223 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3224 MMPLAYER_PRINT_STATE(player);
3226 /* set pipeline status to PAUSED */
3227 ret = __mmplayer_gst_set_state(player,
3228 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3230 if (FALSE == async) {
3231 if (ret != MM_ERROR_NONE) {
3232 GstMessage *msg = NULL;
3233 GTimer *timer = NULL;
3234 gdouble MAX_TIMEOUT_SEC = 3;
3236 LOGE("failed to set state to PAUSED");
3238 if (!player->bus_watcher) {
3239 LOGE("there is no bus msg thread. pipeline is shutting down.");
3243 if (player->msg_posted) {
3244 LOGE("error msg is already posted.");
3248 timer = g_timer_new();
3249 g_timer_start(timer);
3251 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3254 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3256 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3257 GError *error = NULL;
3259 /* parse error code */
3260 gst_message_parse_error(msg, &error, NULL);
3262 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3263 /* Note : the streaming error from the streaming source is handled
3264 * using __mmplayer_handle_streaming_error.
3266 __mmplayer_handle_streaming_error(player, msg);
3269 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3271 if (error->domain == GST_STREAM_ERROR)
3272 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3273 else if (error->domain == GST_RESOURCE_ERROR)
3274 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3275 else if (error->domain == GST_LIBRARY_ERROR)
3276 ret = __mmplayer_gst_handle_library_error(player, error->code);
3277 else if (error->domain == GST_CORE_ERROR)
3278 ret = __mmplayer_gst_handle_core_error(player, error->code);
3280 g_error_free(error);
3282 player->msg_posted = TRUE;
3284 gst_message_unref(msg);
3286 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3288 gst_object_unref(bus);
3289 g_timer_stop(timer);
3290 g_timer_destroy(timer);
3294 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3295 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3297 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3300 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3304 /* generate dot file before returning error */
3305 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3312 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3314 int ret = MM_ERROR_NONE;
3319 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3320 MM_ERROR_PLAYER_NOT_INITIALIZED);
3322 LOGD("current state before doing transition");
3323 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3324 MMPLAYER_PRINT_STATE(player);
3327 LOGD("do async state transition to PLAYING");
3329 /* set pipeline state to PLAYING */
3330 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3332 ret = __mmplayer_gst_set_state(player,
3333 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3334 if (ret != MM_ERROR_NONE) {
3335 LOGE("failed to set state to PLAYING");
3339 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3343 /* generate dot file */
3344 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3351 /* sending event to one of sinkelements */
3353 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3355 GstEvent * event2 = NULL;
3356 GList *sinks = NULL;
3357 gboolean res = FALSE;
3360 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3361 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3363 /* While adding subtitles in live feeds seek is getting called.
3364 Adding defensive check in framework layer.*/
3365 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3366 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3367 LOGE("Should not send seek event during live playback");
3372 if (player->play_subtitle)
3373 event2 = gst_event_copy((const GstEvent *)event);
3375 sinks = player->sink_elements;
3377 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3379 if (GST_IS_ELEMENT(sink)) {
3380 /* keep ref to the event */
3381 gst_event_ref(event);
3383 if ((res = gst_element_send_event(sink, event))) {
3384 LOGD("sending event[%s] to sink element [%s] success!\n",
3385 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3387 /* rtsp case, asyn_done is not called after seek during pause state */
3388 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3389 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3390 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3391 LOGD("RTSP seek completed, after pause state..\n");
3392 player->seek_state = MMPLAYER_SEEK_NONE;
3393 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3399 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3400 sinks = g_list_next(sinks);
3407 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3408 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3411 sinks = g_list_next(sinks);
3414 /* Note : Textbin is not linked to the video or audio bin.
3415 * It needs to send the event to the text sink seperatelly.
3417 if (player->play_subtitle && player->pipeline) {
3418 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3420 if (GST_IS_ELEMENT(text_sink)) {
3421 /* keep ref to the event */
3422 gst_event_ref(event2);
3424 if ((res = gst_element_send_event(text_sink, event2)))
3425 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3426 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3428 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3429 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3431 gst_event_unref(event2);
3435 gst_event_unref(event);
3443 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3444 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3445 gint64 cur, GstSeekType stop_type, gint64 stop)
3447 GstEvent* event = NULL;
3448 gboolean result = FALSE;
3452 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3454 if (player->pipeline && player->pipeline->textbin)
3455 __mmplayer_drop_subtitle(player, FALSE);
3457 event = gst_event_new_seek(rate, format, flags, cur_type,
3458 cur, stop_type, stop);
3460 result = __mmplayer_gst_send_event_to_sink(player, event);
3468 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3470 int ret = MM_ERROR_NONE;
3471 gint64 pos_nsec = 0;
3472 gboolean accurated = FALSE;
3473 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3476 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3477 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3479 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3480 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3483 ret = __mmplayer_gst_check_duration(player, position);
3484 if (ret != MM_ERROR_NONE) {
3485 LOGE("failed to check duration 0x%X", ret);
3486 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3489 if (!__mmplayer_gst_check_seekable(player))
3490 return MM_ERROR_PLAYER_NO_OP;
3492 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3493 position, player->playback_rate, player->duration);
3495 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3496 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3497 This causes problem is position calculation during normal pause resume scenarios also.
3498 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3499 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3500 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3501 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3502 LOGW("getting current position failed in seek");
3504 player->last_position = pos_nsec;
3505 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3508 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3509 LOGD("not completed seek");
3510 return MM_ERROR_PLAYER_DOING_SEEK;
3513 if (!internal_called)
3514 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3516 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3517 that's why set position through property. */
3518 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3519 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3520 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3521 (!player->videodec_linked) && (!player->audiodec_linked)) {
3523 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3524 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3526 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3527 player->seek_state = MMPLAYER_SEEK_NONE;
3528 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3530 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3532 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3534 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3536 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3537 GST_FORMAT_TIME, seek_flags,
3538 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3539 LOGE("failed to set position");
3544 /* NOTE : store last seeking point to overcome some bad operation
3545 * (returning zero when getting current position) of some elements
3547 player->last_position = position;
3549 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3550 if (player->playback_rate > 1.0)
3551 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3553 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3554 LOGD("buffering should be reset after seeking");
3555 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3556 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3560 return MM_ERROR_NONE;
3563 player->pending_seek.is_pending = TRUE;
3564 player->pending_seek.pos = position;
3566 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3567 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3568 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3569 player->pending_seek.pos);
3571 return MM_ERROR_NONE;
3574 player->seek_state = MMPLAYER_SEEK_NONE;
3575 return MM_ERROR_PLAYER_SEEK;
3579 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3581 #define TRICKPLAY_OFFSET GST_MSECOND
3583 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3584 gint64 pos_nsec = 0;
3585 gboolean ret = TRUE;
3587 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3588 MM_ERROR_PLAYER_NOT_INITIALIZED);
3590 current_state = MMPLAYER_CURRENT_STATE(player);
3592 /* NOTE : query position except paused state to overcome some bad operation
3593 * please refer to below comments in details
3595 if (current_state != MM_PLAYER_STATE_PAUSED)
3596 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3598 /* NOTE : get last point to overcome some bad operation of some elements
3599 *(returning zero when getting current position in paused state
3600 * and when failed to get postion during seeking
3602 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3603 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3605 if (player->playback_rate < 0.0)
3606 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3608 pos_nsec = player->last_position;
3611 pos_nsec = player->last_position;
3613 player->last_position = pos_nsec;
3615 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3618 if (player->duration > 0 && pos_nsec > player->duration)
3619 pos_nsec = player->duration;
3621 player->last_position = pos_nsec;
3624 *position = pos_nsec;
3626 return MM_ERROR_NONE;
3629 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3631 #define STREAMING_IS_FINISHED 0
3632 #define BUFFERING_MAX_PER 100
3633 #define DEFAULT_PER_VALUE -1
3634 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3636 MMPlayerGstElement *mainbin = NULL;
3637 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3638 gint64 buffered_total = 0;
3639 gint64 position = 0;
3640 gint buffered_sec = -1;
3641 GstBufferingMode mode = GST_BUFFERING_STREAM;
3642 gint64 content_size_time = player->duration;
3643 guint64 content_size_bytes = player->http_content_size;
3645 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3647 player->pipeline->mainbin,
3648 MM_ERROR_PLAYER_NOT_INITIALIZED);
3650 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3655 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3656 /* and rtsp is not ready yet. */
3657 LOGW("it's only used for http streaming case");
3658 return MM_ERROR_PLAYER_NO_OP;
3661 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3662 LOGW("Time format is not supported yet");
3663 return MM_ERROR_INVALID_ARGUMENT;
3666 if (content_size_time <= 0 || content_size_bytes <= 0) {
3667 LOGW("there is no content size");
3668 return MM_ERROR_NONE;
3671 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3672 LOGW("fail to get current position");
3673 return MM_ERROR_NONE;
3676 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3677 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3679 mainbin = player->pipeline->mainbin;
3680 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3682 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3683 GstQuery *query = NULL;
3684 gint byte_in_rate = 0, byte_out_rate = 0;
3685 gint64 estimated_total = 0;
3687 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3688 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3689 LOGW("fail to get buffering query from queue2");
3691 gst_query_unref(query);
3692 return MM_ERROR_NONE;
3695 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3696 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3698 if (mode == GST_BUFFERING_STREAM) {
3699 /* using only queue in case of push mode(ts / mp3) */
3700 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3701 GST_FORMAT_BYTES, &buffered_total)) {
3702 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3703 stop_per = 100 * buffered_total / content_size_bytes;
3706 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3708 guint num_of_ranges = 0;
3709 gint64 start_byte = 0, stop_byte = 0;
3711 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3712 if (estimated_total != STREAMING_IS_FINISHED) {
3713 /* buffered size info from queue2 */
3714 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3715 for (idx = 0; idx < num_of_ranges; idx++) {
3716 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3717 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3719 buffered_total += (stop_byte - start_byte);
3722 stop_per = BUFFERING_MAX_PER;
3724 gst_query_unref(query);
3727 if (stop_per == DEFAULT_PER_VALUE) {
3728 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3730 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3732 /* buffered size info from multiqueue */
3733 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3734 guint curr_size_bytes = 0;
3735 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3736 "curr-size-bytes", &curr_size_bytes, NULL);
3737 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3738 buffered_total += curr_size_bytes;
3741 if (avg_byterate > 0)
3742 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3743 else if (player->total_maximum_bitrate > 0)
3744 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3745 else if (player->total_bitrate > 0)
3746 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3748 if (buffered_sec >= 0)
3749 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3753 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3754 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3756 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3757 buffered_total, buffered_sec, *start_pos, *stop_pos);
3759 return MM_ERROR_NONE;
3762 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3764 MMHandleType attrs = 0;
3767 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3768 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3770 /* get profile attribute */
3771 attrs = MMPLAYER_GET_ATTRS(player);
3773 LOGE("failed to get content attribute");
3774 return MM_ERROR_PLAYER_INTERNAL;
3777 SECURE_LOGD("uri : %s", player->profile.uri);
3779 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3780 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3781 LOGE("failed to commit");
3783 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3784 return MM_ERROR_PLAYER_INTERNAL;
3786 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3787 return MM_ERROR_PLAYER_INTERNAL;
3789 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3790 return MM_ERROR_PLAYER_INTERNAL;
3793 return MM_ERROR_NONE;
3796 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3798 MMPlayerGstElement *mainbin = NULL;
3799 GstElement *pd_src = NULL;
3800 GstElement *pd_queue = NULL;
3801 GstElement *pd_decodebin = NULL;
3802 GList* element_bucket = NULL;
3803 MMHandleType attrs = 0;
3805 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3808 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3809 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3811 /* get profile attribute */
3812 attrs = MMPLAYER_GET_ATTRS(player);
3814 LOGE("failed to get content attribute");
3815 return MM_ERROR_PLAYER_INTERNAL;
3818 LOGD("http playback with progressive download : %d", player->pd_mode);
3820 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3821 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3822 MMPLAYER_FREEIF(player->pd_file_save_path);
3824 SECURE_LOGD("PD Location : %s", path);
3826 LOGE("filed to find pd location");
3827 return MM_ERROR_PLAYER_INTERNAL;
3830 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3831 LOGE("failed to get storage info");
3832 return MM_ERROR_PLAYER_INTERNAL;
3834 player->pd_file_save_path = g_strdup(path);
3837 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3839 LOGE("failed to create PD push source");
3840 return MM_ERROR_PLAYER_INTERNAL;
3843 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3844 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3846 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3848 mainbin = player->pipeline->mainbin;
3850 /* take source element */
3851 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3852 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3853 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3856 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3857 pd_queue = gst_element_factory_make("queue2", "queue2");
3859 LOGE("failed to create pd buffer element");
3864 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3865 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3866 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3868 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3870 player->streamer->is_pd_mode = TRUE;
3872 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3873 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3874 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3876 pd_decodebin = __mmplayer_create_decodebin(player);
3877 if (!pd_decodebin) {
3878 LOGE("failed to create decodebin");
3882 /* default size of mq in decodebin is 2M
3883 * but it can cause blocking issue during seeking depends on content. */
3884 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3886 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3887 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3889 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3891 /* add elements to pipeline */
3892 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3893 LOGE("failed to add elements to pipeline");
3897 /* linking elements in the bucket by added order. */
3898 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3899 LOGE("failed to link some elements");
3903 g_list_free(element_bucket);
3906 return MM_ERROR_NONE;
3909 MMPLAYER_FREEIF(player->pd_file_save_path);
3910 g_list_free(element_bucket);
3912 if (mainbin[MMPLAYER_M_SRC].gst)
3913 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3915 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3916 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3918 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3919 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3921 mainbin[MMPLAYER_M_SRC].gst = NULL;
3922 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3923 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3925 return MM_ERROR_PLAYER_INTERNAL;
3928 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3930 MMPlayerGstElement *mainbin = NULL;
3931 GstElement* src_elem = NULL;
3932 GstElement *autoplug_elem = NULL;
3933 GList* element_bucket = NULL;
3934 MMHandleType attrs = 0;
3935 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3938 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3939 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3941 /* get profile attribute */
3942 attrs = MMPLAYER_GET_ATTRS(player);
3944 LOGE("failed to get content attribute");
3945 return MM_ERROR_PLAYER_INTERNAL;
3948 LOGD("uri type %d", player->profile.uri_type);
3950 /* create source element */
3951 switch (player->profile.uri_type) {
3952 case MM_PLAYER_URI_TYPE_URL_RTSP:
3953 src_elem = __mmplayer_gst_create_rtsp_src(player);
3955 case MM_PLAYER_URI_TYPE_URL_HTTP:
3956 src_elem = __mmplayer_gst_create_http_src(player);
3958 case MM_PLAYER_URI_TYPE_FILE:
3959 src_elem = __mmplayer_gst_create_file_src(player);
3961 case MM_PLAYER_URI_TYPE_SS:
3963 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3964 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3966 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3970 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3971 LOGD("get timeout from ini");
3972 http_timeout = player->ini.http_timeout;
3975 /* setting property to streaming source */
3976 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3979 case MM_PLAYER_URI_TYPE_MEM:
3981 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3983 src_elem = gst_element_factory_make("appsrc", "mem-source");
3985 LOGE("failed to create appsrc element");
3989 g_object_set(src_elem, "stream-type", stream_type, NULL);
3990 g_object_set(src_elem, "size", player->profile.input_mem.len, NULL);
3991 g_object_set(src_elem, "blocksize", (guint64)20480, NULL);
3993 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3994 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3995 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3996 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4000 LOGE("not support uri type");
4005 LOGE("failed to create source element");
4006 return MM_ERROR_PLAYER_INTERNAL;
4009 mainbin = player->pipeline->mainbin;
4011 /* take source element */
4012 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4014 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4015 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4016 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4018 /* create next element for auto-plugging */
4019 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4020 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4021 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4022 if (!autoplug_elem) {
4023 LOGE("failed to create typefind element");
4027 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4028 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4029 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4030 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4031 autoplug_elem = __mmplayer_create_decodebin(player);
4032 if (!autoplug_elem) {
4033 LOGE("failed to create decodebin");
4037 /* default size of mq in decodebin is 2M
4038 * but it can cause blocking issue during seeking depends on content. */
4039 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4042 if (autoplug_elem) {
4043 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4044 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4045 mainbin[autoplug_elem_id].gst = autoplug_elem;
4047 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4050 /* add elements to pipeline */
4051 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4052 LOGE("failed to add elements to pipeline");
4056 /* linking elements in the bucket by added order. */
4057 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4058 LOGE("failed to link some elements");
4062 /* FIXME: need to check whether this is required or not. */
4063 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4064 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4065 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4066 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4068 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4069 LOGE("failed to create fakesink");
4072 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4074 /* take ownership of fakesink. we are reusing it */
4075 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4077 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4078 LOGE("failed to add fakesink to bin");
4079 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4084 g_list_free(element_bucket);
4087 return MM_ERROR_NONE;
4090 g_list_free(element_bucket);
4092 if (mainbin[MMPLAYER_M_SRC].gst)
4093 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4095 if (mainbin[autoplug_elem_id].gst)
4096 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4098 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4099 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4101 mainbin[MMPLAYER_M_SRC].gst = NULL;
4102 mainbin[autoplug_elem_id].gst = NULL;
4103 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4105 return MM_ERROR_PLAYER_INTERNAL;
4108 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4111 MMPlayerGstElement *mainbin = NULL;
4114 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4115 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4117 mainbin = player->pipeline->mainbin;
4119 /* connect bus callback */
4120 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4122 LOGE("cannot get bus from pipeline");
4123 return MM_ERROR_PLAYER_INTERNAL;
4126 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4127 player->context.thread_default = g_main_context_get_thread_default();
4128 if (player->context.thread_default == NULL) {
4129 player->context.thread_default = g_main_context_default();
4130 LOGD("thread-default context is the global default context");
4132 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4134 /* set sync handler to get tag synchronously */
4135 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4136 gst_object_unref(GST_OBJECT(bus));
4138 /* create gst bus_msb_cb thread */
4139 g_mutex_init(&player->bus_msg_thread_mutex);
4140 g_cond_init(&player->bus_msg_thread_cond);
4141 player->bus_msg_thread_exit = FALSE;
4142 player->bus_msg_thread =
4143 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4144 if (!player->bus_msg_thread) {
4145 LOGE("failed to create gst BUS msg thread");
4146 g_mutex_clear(&player->bus_msg_thread_mutex);
4147 g_cond_clear(&player->bus_msg_thread_cond);
4148 return MM_ERROR_PLAYER_INTERNAL;
4152 return MM_ERROR_NONE;
4155 GstElement* __mmplayer_gst_build_source(mm_player_t* player)
4157 GstElement* element = NULL;
4160 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4161 player->pipeline->mainbin, NULL);
4163 /* setup source for gapless play */
4164 switch (player->profile.uri_type) {
4166 case MM_PLAYER_URI_TYPE_FILE:
4167 element = __mmplayer_gst_create_file_src(player);
4169 case MM_PLAYER_URI_TYPE_URL_HTTP:
4170 element = __mmplayer_gst_create_http_src(player);
4173 LOGE("not support uri type %d", player->profile.uri_type);
4178 LOGE("failed to create source element");