4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <mm_attrs_private.h>
31 #include <gst/app/gstappsrc.h>
33 #include "mm_player_gst.h"
34 #include "mm_player_priv.h"
35 #include "mm_player_attrs.h"
36 #include "mm_player_utils.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
86 /* NOTE : decide gstreamer state whether there is some playable track or not. */
88 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
90 gchar *src_element_name = NULL;
91 GstElement *src_element = NULL;
92 GstElementFactory *factory = NULL;
93 const gchar* klass = NULL;
97 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
98 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
99 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
100 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
102 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
104 src_element = GST_ELEMENT_CAST(message->src);
108 src_element_name = GST_ELEMENT_NAME(src_element);
109 if (!src_element_name)
112 factory = gst_element_get_factory(src_element);
116 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
120 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
121 error->code, error->message, src_element_name, klass);
123 /* check whether the error is posted from not-activated track or not */
124 if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
126 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
127 LOGD("current active pad index -%d", active_pad_index);
129 if (src_element_name) {
132 if (player->audio_decoders) {
133 GList *adec = player->audio_decoders;
134 for (; adec ; adec = g_list_next(adec)) {
135 gchar *name = adec->data;
137 LOGD("found audio decoder name = %s", name);
138 if (g_strrstr(name, src_element_name)) {
145 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
148 if (active_pad_index != msg_src_pos) {
149 LOGD("skip error because error is posted from no activated track");
150 return MM_ERROR_NONE;
154 switch (error->code) {
155 case GST_STREAM_ERROR_DECODE:
157 /* Demuxer can't parse one track because it's corrupted.
158 * So, the decoder for it is not linked.
159 * But, it has one playable track.
161 if (g_strrstr(klass, "Demux")) {
162 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
167 if (player->pipeline->audiobin) // PCM
168 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
170 goto CODEC_NOT_FOUND;
173 return MM_ERROR_PLAYER_INVALID_STREAM;
177 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
178 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
179 case GST_STREAM_ERROR_WRONG_TYPE:
181 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
182 LOGE("Not supported subtitle.");
183 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
185 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
188 case GST_STREAM_ERROR_FAILED:
190 /* Decoder Custom Message */
191 if (strstr(error->message, "ongoing")) {
192 if (strncasecmp(klass, "audio", 5)) {
193 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
194 LOGD("Video can keep playing.\n");
195 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
197 goto CODEC_NOT_FOUND;
199 } else if (strncasecmp(klass, "video", 5)) {
200 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
201 LOGD("Audio can keep playing.\n");
202 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
204 goto CODEC_NOT_FOUND;
207 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
211 case GST_STREAM_ERROR_DECRYPT:
212 case GST_STREAM_ERROR_DECRYPT_NOKEY:
214 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
216 if (strstr(error->message, "rights expired"))
217 return MM_ERROR_PLAYER_DRM_EXPIRED;
218 else if (strstr(error->message, "no rights"))
219 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
220 else if (strstr(error->message, "has future rights"))
221 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
222 else if (strstr(error->message, "opl violation"))
223 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
224 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
234 return MM_ERROR_PLAYER_INVALID_STREAM;
237 return MM_ERROR_PLAYER_INTERNAL;
240 LOGD("not found any available codec. Player should be destroyed.\n");
241 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
245 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
247 gint trans_err = MM_ERROR_NONE;
251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
254 case GST_CORE_ERROR_MISSING_PLUGIN:
255 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
256 case GST_CORE_ERROR_STATE_CHANGE:
257 case GST_CORE_ERROR_SEEK:
258 case GST_CORE_ERROR_NOT_IMPLEMENTED:
259 case GST_CORE_ERROR_FAILED:
260 case GST_CORE_ERROR_TOO_LAZY:
261 case GST_CORE_ERROR_PAD:
262 case GST_CORE_ERROR_THREAD:
263 case GST_CORE_ERROR_NEGOTIATION:
264 case GST_CORE_ERROR_EVENT:
265 case GST_CORE_ERROR_CAPS:
266 case GST_CORE_ERROR_TAG:
267 case GST_CORE_ERROR_CLOCK:
268 case GST_CORE_ERROR_DISABLED:
270 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
280 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
282 gint trans_err = MM_ERROR_NONE;
286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
289 case GST_LIBRARY_ERROR_FAILED:
290 case GST_LIBRARY_ERROR_TOO_LAZY:
291 case GST_LIBRARY_ERROR_INIT:
292 case GST_LIBRARY_ERROR_SHUTDOWN:
293 case GST_LIBRARY_ERROR_SETTINGS:
294 case GST_LIBRARY_ERROR_ENCODE:
296 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
306 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
308 gint trans_err = MM_ERROR_NONE;
312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
315 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
316 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
318 case GST_RESOURCE_ERROR_NOT_FOUND:
319 case GST_RESOURCE_ERROR_OPEN_READ:
320 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
321 || MMPLAYER_IS_RTSP_STREAMING(player)) {
322 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
325 case GST_RESOURCE_ERROR_READ:
326 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
327 || MMPLAYER_IS_RTSP_STREAMING(player)) {
328 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
330 } else if (message != NULL && message->src != NULL) {
331 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
332 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
334 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
335 path_type = MMPLAYER_PATH_VOD;
336 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
337 path_type = MMPLAYER_PATH_TEXT;
339 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
340 /* check storage state */
341 storage_get_state(player->storage_info[path_type].id, &storage_state);
342 player->storage_info[path_type].state = storage_state;
343 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
346 case GST_RESOURCE_ERROR_WRITE:
347 case GST_RESOURCE_ERROR_FAILED:
348 case GST_RESOURCE_ERROR_SEEK:
349 case GST_RESOURCE_ERROR_TOO_LAZY:
350 case GST_RESOURCE_ERROR_BUSY:
351 case GST_RESOURCE_ERROR_OPEN_WRITE:
352 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
353 case GST_RESOURCE_ERROR_CLOSE:
354 case GST_RESOURCE_ERROR_SYNC:
355 case GST_RESOURCE_ERROR_SETTINGS:
357 trans_err = MM_ERROR_PLAYER_INTERNAL;
367 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
369 gint trans_err = MM_ERROR_NONE;
373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
374 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
375 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
377 switch (error->code) {
378 case GST_STREAM_ERROR_FAILED:
379 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
380 case GST_STREAM_ERROR_DECODE:
381 case GST_STREAM_ERROR_WRONG_TYPE:
382 case GST_STREAM_ERROR_DECRYPT:
383 case GST_STREAM_ERROR_DECRYPT_NOKEY:
384 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
385 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
388 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
389 case GST_STREAM_ERROR_TOO_LAZY:
390 case GST_STREAM_ERROR_ENCODE:
391 case GST_STREAM_ERROR_DEMUX:
392 case GST_STREAM_ERROR_MUX:
393 case GST_STREAM_ERROR_FORMAT:
395 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
405 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
407 MMMessageParamType msg_param;
408 gchar *msg_src_element;
412 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
413 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
415 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
417 memset(&msg_param, 0, sizeof(MMMessageParamType));
419 if (error->domain == GST_CORE_ERROR) {
420 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
421 } else if (error->domain == GST_LIBRARY_ERROR) {
422 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
423 } else if (error->domain == GST_RESOURCE_ERROR) {
424 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
425 } else if (error->domain == GST_STREAM_ERROR) {
426 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
428 LOGW("This error domain is not defined.\n");
430 /* we treat system error as an internal error */
431 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
435 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
437 msg_param.data = (void *) error->message;
439 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
440 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
444 if (msg_param.code == MM_ERROR_NONE)
447 /* skip error to avoid duplicated posting */
448 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
449 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
450 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
451 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
453 /* The error will be handled by mused.
454 * @ref _mmplayer_manage_external_storage_state() */
456 LOGW("storage is removed, skip error post");
460 /* post error to application */
461 if (!player->msg_posted) {
462 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
463 /* don't post more if one was sent already */
464 player->msg_posted = TRUE;
466 LOGD("skip error post because it's sent already.\n");
474 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
477 MMMessageParamType msg_param;
478 gchar *msg_src_element = NULL;
479 GstStructure *s = NULL;
481 gchar *error_string = NULL;
485 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
486 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
488 s = gst_structure_copy(gst_message_get_structure(message));
491 if (!gst_structure_get_uint(s, "error_id", &error_id))
492 error_id = MMPLAYER_STREAMING_ERROR_NONE;
495 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
498 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
501 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
504 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
507 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
510 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
513 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
516 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
519 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
522 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
525 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
528 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
531 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
534 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
540 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
543 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
546 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
549 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
552 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
555 case MMPLAYER_STREAMING_ERROR_GONE:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
558 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
561 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
564 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
567 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
570 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
573 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
576 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
579 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
582 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
585 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
588 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
591 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
594 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
597 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
600 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
603 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
606 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
607 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
609 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
610 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
612 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
613 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
615 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
616 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
618 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
619 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
621 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
622 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
624 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
625 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
627 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
628 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
632 gst_structure_free(s);
633 return MM_ERROR_PLAYER_STREAMING_FAIL;
637 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
639 msg_param.data = (void *) error_string;
642 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
644 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
645 msg_src_element, msg_param.code, (char*)msg_param.data);
648 /* post error to application */
649 if (!player->msg_posted) {
650 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
652 /* don't post more if one was sent already */
653 player->msg_posted = TRUE;
655 LOGD("skip error post because it's sent already.\n");
657 gst_structure_free(s);
658 g_free(error_string);
666 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
668 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
669 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
670 gst_tag_list_get_string(tags, "stitching_software",
671 &metadata->stitching_software);
672 gst_tag_list_get_string(tags, "projection_type",
673 &metadata->projection_type_string);
674 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
675 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
676 gst_tag_list_get_int(tags, "init_view_heading",
677 &metadata->init_view_heading);
678 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
679 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
680 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
681 gst_tag_list_get_int(tags, "full_pano_width_pixels",
682 &metadata->full_pano_width_pixels);
683 gst_tag_list_get_int(tags, "full_pano_height_pixels",
684 &metadata->full_pano_height_pixels);
685 gst_tag_list_get_int(tags, "cropped_area_image_width",
686 &metadata->cropped_area_image_width);
687 gst_tag_list_get_int(tags, "cropped_area_image_height",
688 &metadata->cropped_area_image_height);
689 gst_tag_list_get_int(tags, "cropped_area_left",
690 &metadata->cropped_area_left);
691 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
692 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
693 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
694 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
698 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
701 /* macro for better code readability */
702 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
703 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
704 if (string != NULL) { \
705 SECURE_LOGD("update tag string : %s\n", string); \
706 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
707 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
708 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
709 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
710 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
711 g_free(new_string); \
714 mm_attrs_set_string_by_name(attribute, playertag, string); \
721 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
723 GstSample *sample = NULL;\
724 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
725 GstMapInfo info = GST_MAP_INFO_INIT;\
726 buffer = gst_sample_get_buffer(sample);\
727 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
728 LOGD("failed to get image data from tag");\
729 gst_sample_unref(sample);\
732 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
733 MMPLAYER_FREEIF(player->album_art);\
734 player->album_art = (gchar *)g_malloc(info.size);\
735 if (player->album_art) {\
736 memcpy(player->album_art, info.data, info.size);\
737 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
738 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
739 msg_param.data = (void *)player->album_art;\
740 msg_param.size = info.size;\
741 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
742 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
745 gst_buffer_unmap(buffer, &info);\
746 gst_sample_unref(sample);\
750 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
752 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
755 gchar *tag_list_str = NULL; \
756 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
757 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
758 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
759 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
760 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
762 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
763 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
764 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
765 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
766 player->bitrate[track_type] = v_uint; \
767 player->total_bitrate = 0; \
768 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
769 player->total_bitrate += player->bitrate[i]; \
770 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
771 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
772 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
773 player->maximum_bitrate[track_type] = v_uint; \
774 player->total_maximum_bitrate = 0; \
775 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
776 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
777 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
778 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
780 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
783 g_free(tag_list_str); \
788 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
789 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
791 string = g_strdup_printf("%d", g_date_get_year(date));\
792 mm_attrs_set_string_by_name(attribute, playertag, string);\
793 SECURE_LOGD("metainfo year : %s\n", string);\
794 MMPLAYER_FREEIF(string);\
799 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
800 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
801 if (datetime != NULL) {\
802 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
803 mm_attrs_set_string_by_name(attribute, playertag, string);\
804 SECURE_LOGD("metainfo year : %s\n", string);\
805 MMPLAYER_FREEIF(string);\
806 gst_date_time_unref(datetime);\
810 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
811 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
813 /* FIXIT : don't know how to store date */\
819 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
820 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
822 /* FIXIT : don't know how to store date */\
829 GstTagList* tag_list = NULL;
831 MMHandleType attrs = 0;
836 GstDateTime *datetime = NULL;
838 GstBuffer *buffer = NULL;
840 MMMessageParamType msg_param = {0, };
842 /* currently not used. but those are needed for above macro */
843 //guint64 v_uint64 = 0;
844 //gdouble v_double = 0;
846 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
848 attrs = MMPLAYER_GET_ATTRS(player);
850 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
852 /* get tag list from gst message */
853 gst_message_parse_tag(msg, &tag_list);
855 /* store tags to player attributes */
856 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
857 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
858 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
859 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
860 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
861 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
862 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
863 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
864 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
865 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
866 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
867 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
868 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
869 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
870 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
871 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
872 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
874 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
876 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
877 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
878 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
883 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
884 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
885 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
887 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
888 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
889 MMPLAYER_UPDATE_TAG_LOCK(player);
890 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
891 MMPLAYER_UPDATE_TAG_UNLOCK(player);
892 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
901 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
903 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
904 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
906 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
907 if (player->video360_metadata.is_spherical == -1) {
908 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
909 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
910 player->video360_metadata.is_spherical);
911 if (player->video360_metadata.is_spherical == 1) {
912 LOGD("This is spherical content for 360 playback.");
913 player->is_content_spherical = TRUE;
915 LOGD("This is not spherical content");
916 player->is_content_spherical = FALSE;
919 if (player->video360_metadata.projection_type_string) {
920 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
921 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
923 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
924 player->is_content_spherical = player->is_video360_enabled = FALSE;
928 if (player->video360_metadata.stereo_mode_string) {
929 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
930 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
931 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
932 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
933 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
934 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
936 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
937 player->is_content_spherical = player->is_video360_enabled = FALSE;
943 if (mmf_attrs_commit(attrs))
944 LOGE("failed to commit.\n");
946 gst_tag_list_free(tag_list);
951 /* if retval is FALSE, it will be dropped for perfomance. */
953 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
955 gboolean retval = FALSE;
957 if (!(player->pipeline && player->pipeline->mainbin)) {
958 LOGE("player pipeline handle is null");
962 switch (GST_MESSAGE_TYPE(message)) {
963 case GST_MESSAGE_TAG:
964 case GST_MESSAGE_EOS:
965 case GST_MESSAGE_ERROR:
966 case GST_MESSAGE_WARNING:
967 case GST_MESSAGE_CLOCK_LOST:
968 case GST_MESSAGE_NEW_CLOCK:
969 case GST_MESSAGE_ELEMENT:
970 case GST_MESSAGE_DURATION_CHANGED:
971 case GST_MESSAGE_ASYNC_START:
974 case GST_MESSAGE_ASYNC_DONE:
975 case GST_MESSAGE_STATE_CHANGED:
976 /* we only handle messages from pipeline */
977 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
982 case GST_MESSAGE_BUFFERING:
984 gint buffer_percent = 0;
987 gst_message_parse_buffering(message, &buffer_percent);
988 if (buffer_percent != MAX_BUFFER_PERCENT) {
989 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
993 if (!MMPLAYER_CMD_TRYLOCK(player)) {
994 LOGW("can't get cmd lock, send msg to bus");
998 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
999 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1000 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1003 MMPLAYER_CMD_UNLOCK(player);
1016 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1018 MMHandleType attrs = 0;
1019 guint64 data_size = 0;
1021 gint64 pos_nsec = 0;
1024 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1026 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1028 attrs = MMPLAYER_GET_ATTRS(player);
1030 LOGE("fail to get attributes.\n");
1034 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1035 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1037 if (stat(path, &sb) == 0)
1038 data_size = (guint64)sb.st_size;
1039 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1040 data_size = player->http_content_size;
1043 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1044 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1050 __mmplayer_handle_buffering_playback(mm_player_t* player)
1052 int ret = MM_ERROR_NONE;
1053 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1054 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1055 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1056 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1058 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1059 LOGW("do nothing for buffering msg\n");
1060 ret = MM_ERROR_PLAYER_INVALID_STATE;
1064 prev_state = MMPLAYER_PREV_STATE(player);
1065 current_state = MMPLAYER_CURRENT_STATE(player);
1066 target_state = MMPLAYER_TARGET_STATE(player);
1067 pending_state = MMPLAYER_PENDING_STATE(player);
1069 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1070 MMPLAYER_STATE_GET_NAME(prev_state),
1071 MMPLAYER_STATE_GET_NAME(current_state),
1072 MMPLAYER_STATE_GET_NAME(pending_state),
1073 MMPLAYER_STATE_GET_NAME(target_state),
1074 player->streamer->buffering_state);
1076 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1077 /* NOTE : if buffering has done, player has to go to target state. */
1078 switch (target_state) {
1079 case MM_PLAYER_STATE_PAUSED:
1081 switch (pending_state) {
1082 case MM_PLAYER_STATE_PLAYING:
1083 __mmplayer_gst_pause(player, TRUE);
1086 case MM_PLAYER_STATE_PAUSED:
1087 LOGD("player is already going to paused state, there is nothing to do.\n");
1090 case MM_PLAYER_STATE_NONE:
1091 case MM_PLAYER_STATE_NULL:
1092 case MM_PLAYER_STATE_READY:
1094 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1100 case MM_PLAYER_STATE_PLAYING:
1102 switch (pending_state) {
1103 case MM_PLAYER_STATE_NONE:
1105 if (current_state != MM_PLAYER_STATE_PLAYING)
1106 __mmplayer_gst_resume(player, TRUE);
1110 case MM_PLAYER_STATE_PAUSED:
1111 /* NOTE: It should be worked as asynchronously.
1112 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1114 if (current_state == MM_PLAYER_STATE_PLAYING) {
1115 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1116 * The current state should be changed to paused purposely to prevent state conflict.
1118 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1120 __mmplayer_gst_resume(player, TRUE);
1123 case MM_PLAYER_STATE_PLAYING:
1124 LOGD("player is already going to playing state, there is nothing to do.\n");
1127 case MM_PLAYER_STATE_NULL:
1128 case MM_PLAYER_STATE_READY:
1130 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1136 case MM_PLAYER_STATE_NULL:
1137 case MM_PLAYER_STATE_READY:
1138 case MM_PLAYER_STATE_NONE:
1140 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1144 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1145 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1147 switch (pending_state) {
1148 case MM_PLAYER_STATE_NONE:
1150 if (current_state != MM_PLAYER_STATE_PAUSED) {
1151 /* rtsp streaming pause makes rtsp server stop sending data. */
1152 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1153 LOGD("set pause state during buffering\n");
1154 __mmplayer_gst_pause(player, TRUE);
1160 case MM_PLAYER_STATE_PLAYING:
1161 /* rtsp streaming pause makes rtsp server stop sending data. */
1162 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1163 __mmplayer_gst_pause(player, TRUE);
1166 case MM_PLAYER_STATE_PAUSED:
1169 case MM_PLAYER_STATE_NULL:
1170 case MM_PLAYER_STATE_READY:
1172 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1181 static VariantData *
1182 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1184 VariantData *var_info = NULL;
1185 g_return_val_if_fail(self != NULL, NULL);
1187 var_info = g_new0(VariantData, 1);
1188 if (!var_info) return NULL;
1189 var_info->bandwidth = self->bandwidth;
1190 var_info->width = self->width;
1191 var_info->height = self->height;
1196 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1202 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1203 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1205 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1206 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1207 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1209 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1210 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1211 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1214 /* handling audio clip which has vbr. means duration is keep changing */
1215 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1224 __mmplayer_eos_timer_cb(gpointer u_data)
1226 mm_player_t* player = NULL;
1227 MMHandleType attrs = 0;
1230 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1232 player = (mm_player_t*) u_data;
1233 attrs = MMPLAYER_GET_ATTRS(player);
1235 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1239 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1240 if (ret_value != MM_ERROR_NONE)
1241 LOGE("seeking to 0 failed in repeat play");
1244 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1247 /* we are returning FALSE as we need only one posting */
1252 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1254 MMPLAYER_RETURN_IF_FAIL(player);
1256 /* post now if delay is zero */
1257 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
1258 LOGD("eos delay is zero. posting EOS now\n");
1259 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1261 if (player->set_mode.pcm_extraction)
1262 __mmplayer_cancel_eos_timer(player);
1267 /* cancel if existing */
1268 __mmplayer_cancel_eos_timer(player);
1270 /* init new timeout */
1271 /* NOTE : consider give high priority to this timer */
1272 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1274 player->eos_timer = g_timeout_add(delay_in_ms,
1275 __mmplayer_eos_timer_cb, player);
1277 player->context.global_default = g_main_context_default();
1278 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1280 /* check timer is valid. if not, send EOS now */
1281 if (player->eos_timer == 0) {
1282 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1283 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1287 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1289 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1290 int ret = MM_ERROR_NONE;
1294 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1296 if (!player->pending_seek.is_pending) {
1297 LOGD("pending seek is not reserved. nothing to do.\n");
1301 /* check player state if player could pending seek or not. */
1302 current_state = MMPLAYER_CURRENT_STATE(player);
1304 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1305 LOGW("try to pending seek in %s state, try next time. \n",
1306 MMPLAYER_STATE_GET_NAME(current_state));
1310 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1312 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1314 if (MM_ERROR_NONE != ret)
1315 LOGE("failed to seek pending postion. just keep staying current position.\n");
1317 player->pending_seek.is_pending = FALSE;
1325 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1327 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1329 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1331 audiobin = player->pipeline->audiobin; /* can be null */
1332 videobin = player->pipeline->videobin; /* can be null */
1333 textbin = player->pipeline->textbin; /* can be null */
1335 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1337 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1338 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1340 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1341 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1343 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1344 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1350 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1352 MMPlayerGstElement *textbin;
1355 MMPLAYER_RETURN_IF_FAIL(player &&
1357 player->pipeline->textbin);
1359 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1361 textbin = player->pipeline->textbin;
1364 LOGD("Drop subtitle text after getting EOS\n");
1366 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1367 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1369 player->is_subtitle_force_drop = TRUE;
1371 if (player->is_subtitle_force_drop == TRUE) {
1372 LOGD("Enable subtitle data path without drop\n");
1374 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1375 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1377 LOGD("non-connected with external display");
1379 player->is_subtitle_force_drop = FALSE;
1385 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1387 MMHandleType attrs = 0;
1392 /* NOTE : EOS event is comming multiple time. watch out it */
1393 /* check state. we only process EOS when pipeline state goes to PLAYING */
1394 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1395 LOGD("EOS received on non-playing state. ignoring it");
1399 if (player->pipeline) {
1400 if (player->pipeline->textbin)
1401 __mmplayer_drop_subtitle(player, TRUE);
1403 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1406 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1408 LOGD("release audio callback");
1410 /* release audio callback */
1411 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1412 player->audio_cb_probe_id = 0;
1413 /* audio callback should be free because it can be called even though probe remove.*/
1414 player->audio_stream_cb = NULL;
1415 player->audio_stream_cb_user_param = NULL;
1419 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1420 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1422 /* rewind if repeat count is greater then zero */
1423 /* get play count */
1424 attrs = MMPLAYER_GET_ATTRS(player);
1427 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1429 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1431 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1432 if (player->playback_rate < 0.0) {
1433 player->resumed_by_rewind = TRUE;
1434 _mmplayer_set_mute((MMHandleType)player, 0);
1435 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1438 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1441 player->sent_bos = FALSE;
1443 LOGD("do not post eos msg for repeating");
1448 if (player->pipeline)
1449 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1451 /* post eos message to application */
1452 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1454 /* reset last position */
1455 player->last_position = 0;
1462 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1464 GError *error = NULL;
1465 gchar* debug = NULL;
1469 /* generating debug info before returning error */
1470 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1472 /* get error code */
1473 gst_message_parse_error(msg, &error, &debug);
1475 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1476 /* Note : the streaming error from the streaming source is handled
1477 * using __mmplayer_handle_streaming_error.
1479 __mmplayer_handle_streaming_error(player, msg);
1481 /* dump state of all element */
1482 __mmplayer_dump_pipeline_state(player);
1484 /* traslate gst error code to msl error code. then post it
1485 * to application if needed
1487 __mmplayer_handle_gst_error(player, msg, error);
1490 LOGE("error debug : %s", debug);
1493 if (MMPLAYER_IS_HTTP_PD(player))
1494 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1496 MMPLAYER_FREEIF(debug);
1497 g_error_free(error);
1504 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1506 MMMessageParamType msg_param = {0, };
1507 int bRet = MM_ERROR_NONE;
1510 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1512 if (!MMPLAYER_IS_STREAMING(player)) {
1513 LOGW("this is not streaming playback.");
1517 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1518 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1519 /* skip the playback control by buffering msg while user request is handled. */
1522 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1524 gst_message_parse_buffering(msg, &per);
1525 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1527 msg_param.connection.buffering = per;
1528 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1532 MMPLAYER_CMD_LOCK(player);
1535 if (!player->streamer) {
1536 LOGW("Pipeline is shutting down");
1537 MMPLAYER_CMD_UNLOCK(player);
1541 /* ignore the remained buffering message till getting 100% msg */
1542 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1543 gint buffer_percent = 0;
1545 gst_message_parse_buffering(msg, &buffer_percent);
1547 if (buffer_percent == MAX_BUFFER_PERCENT) {
1548 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1549 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1551 MMPLAYER_CMD_UNLOCK(player);
1555 /* ignore the remained buffering message */
1556 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1557 gint buffer_percent = 0;
1559 gst_message_parse_buffering(msg, &buffer_percent);
1561 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1562 player->streamer->buffering_percent, buffer_percent);
1564 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1565 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1566 player->streamer->buffering_req.is_pre_buffering = FALSE;
1568 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1570 LOGD("interrupted buffering - ignored the remained buffering msg!");
1571 MMPLAYER_CMD_UNLOCK(player);
1576 __mmplayer_update_buffer_setting(player, msg);
1578 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1580 if (bRet == MM_ERROR_NONE) {
1581 msg_param.connection.buffering = player->streamer->buffering_percent;
1582 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1584 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1585 player->pending_resume &&
1586 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1588 player->is_external_subtitle_added_now = FALSE;
1589 player->pending_resume = FALSE;
1590 _mmplayer_resume((MMHandleType)player);
1593 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1594 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1596 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1597 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1598 player->seek_state = MMPLAYER_SEEK_NONE;
1599 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1600 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1601 /* Considering the async state trasition in case of RTSP.
1602 After getting state change gst msg, seek cmpleted msg will be posted. */
1603 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1607 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1608 if (!player->streamer) {
1609 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1610 MMPLAYER_CMD_UNLOCK(player);
1614 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1616 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1617 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1619 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1620 msg_param.connection.buffering = player->streamer->buffering_percent;
1621 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1623 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1626 msg_param.connection.buffering = player->streamer->buffering_percent;
1627 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1630 MMPLAYER_CMD_UNLOCK(player);
1638 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1640 MMPlayerGstElement *mainbin;
1641 const GValue *voldstate, *vnewstate, *vpending;
1642 GstState oldstate = GST_STATE_NULL;
1643 GstState newstate = GST_STATE_NULL;
1644 GstState pending = GST_STATE_NULL;
1647 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1649 mainbin = player->pipeline->mainbin;
1651 /* we only handle messages from pipeline */
1652 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1655 /* get state info from msg */
1656 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1657 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1658 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1660 if (!voldstate || !vnewstate) {
1661 LOGE("received msg has wrong format.");
1665 oldstate = (GstState)voldstate->data[0].v_int;
1666 newstate = (GstState)vnewstate->data[0].v_int;
1668 pending = (GstState)vpending->data[0].v_int;
1670 LOGD("state changed [%s] : %s ---> %s final : %s",
1671 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1672 gst_element_state_get_name((GstState)oldstate),
1673 gst_element_state_get_name((GstState)newstate),
1674 gst_element_state_get_name((GstState)pending));
1676 if (newstate == GST_STATE_PLAYING) {
1677 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1679 int retVal = MM_ERROR_NONE;
1680 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1682 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1684 if (MM_ERROR_NONE != retVal)
1685 LOGE("failed to seek pending postion. just keep staying current position.");
1687 player->pending_seek.is_pending = FALSE;
1691 if (oldstate == newstate) {
1692 LOGD("pipeline reports state transition to old state");
1697 case GST_STATE_PAUSED:
1699 gboolean prepare_async = FALSE;
1701 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1702 __mmplayer_configure_audio_callback(player);
1704 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1705 // managed prepare async case
1706 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1707 LOGD("checking prepare mode for async transition - %d", prepare_async);
1710 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1711 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1713 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1714 __mm_player_streaming_set_content_bitrate(player->streamer,
1715 player->total_maximum_bitrate, player->total_bitrate);
1717 if (player->pending_seek.is_pending) {
1718 LOGW("trying to do pending seek");
1719 MMPLAYER_CMD_LOCK(player);
1720 __mmplayer_gst_pending_seek(player);
1721 MMPLAYER_CMD_UNLOCK(player);
1727 case GST_STATE_PLAYING:
1729 if (MMPLAYER_IS_STREAMING(player)) {
1730 // managed prepare async case when buffering is completed
1731 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1732 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1733 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1734 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1736 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1738 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1739 if (player->streamer->buffering_percent < 100) {
1741 MMMessageParamType msg_param = {0, };
1742 LOGW("Posting Buffering Completed Message to Application !!!");
1744 msg_param.connection.buffering = 100;
1745 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1750 if (player->gapless.stream_changed) {
1751 __mmplayer_update_content_attrs(player, ATTR_ALL);
1752 player->gapless.stream_changed = FALSE;
1755 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1756 player->seek_state = MMPLAYER_SEEK_NONE;
1757 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1761 case GST_STATE_VOID_PENDING:
1762 case GST_STATE_NULL:
1763 case GST_STATE_READY:
1773 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1775 const gchar *structure_name;
1776 gint count = 0, idx = 0;
1777 MMHandleType attrs = 0;
1780 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1782 attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("Failed to get content attribute");
1788 if (gst_message_get_structure(msg) == NULL)
1791 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1792 if (!structure_name)
1795 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1797 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1798 const GValue *var_info = NULL;
1800 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1801 if (var_info != NULL) {
1802 if (player->adaptive_info.var_list)
1803 g_list_free_full(player->adaptive_info.var_list, g_free);
1805 /* share addr or copy the list */
1806 player->adaptive_info.var_list =
1807 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1809 count = g_list_length(player->adaptive_info.var_list);
1811 VariantData *temp = NULL;
1813 /* print out for debug */
1814 LOGD("num of variant_info %d", count);
1815 for (idx = 0; idx < count; idx++) {
1816 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1818 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1824 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1825 gint num_buffers = 0;
1826 gint extra_num_buffers = 0;
1828 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1829 player->video_num_buffers = num_buffers;
1830 LOGD("video_num_buffers : %d", player->video_num_buffers);
1833 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1834 player->video_extra_num_buffers = extra_num_buffers;
1835 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1840 if (!strcmp(structure_name, "Language_list")) {
1841 const GValue *lang_list = NULL;
1842 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1843 if (lang_list != NULL) {
1844 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1846 LOGD("Total audio tracks(from parser) = %d \n", count);
1850 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1851 const GValue *lang_list = NULL;
1852 MMPlayerLangStruct *temp = NULL;
1854 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1855 if (lang_list != NULL) {
1856 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1858 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1859 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1860 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1861 if (mmf_attrs_commit(attrs))
1862 LOGE("failed to commit.\n");
1863 LOGD("Total subtitle tracks = %d \n", count);
1866 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1868 LOGD("value of lang_key is %s and lang_code is %s",
1869 temp->language_key, temp->language_code);
1872 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1873 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1878 /* custom message */
1879 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1880 MMMessageParamType msg_param = {0,};
1881 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1882 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1885 /* custom message for RTSP attribute :
1886 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1887 sdp which has contents info is received when rtsp connection is opened.
1888 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1889 if (!strcmp(structure_name, "rtspsrc_properties")) {
1891 gchar *audio_codec = NULL;
1892 gchar *video_codec = NULL;
1893 gchar *video_frame_size = NULL;
1895 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1896 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1897 player->streaming_type = __mmplayer_get_stream_service_type(player);
1899 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1900 LOGD("rtsp_audio_codec : %s", audio_codec);
1902 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1904 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1905 LOGD("rtsp_video_codec : %s", video_codec);
1907 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1909 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1910 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1911 if (video_frame_size) {
1913 char *seperator = strchr(video_frame_size, '-');
1916 char video_width[10] = {0,};
1917 int frame_size_len = strlen(video_frame_size);
1918 int separtor_len = strlen(seperator);
1920 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1921 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1924 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1928 if (mmf_attrs_commit(attrs))
1929 LOGE("failed to commit.\n");
1937 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1939 MMPlayerGstElement *mainbin;
1942 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1944 mainbin = player->pipeline->mainbin;
1946 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1948 /* we only handle messages from pipeline */
1949 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1952 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1953 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1954 player->seek_state = MMPLAYER_SEEK_NONE;
1955 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1956 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1957 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1958 LOGD("sync %s state(%s) with parent state(%s)",
1959 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1960 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1961 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1963 /* In case of streaming, pause is required before finishing seeking by buffering.
1964 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1965 Because the buffering state is controlled according to the state transition for force resume,
1966 the decodebin state should be paused as player state. */
1967 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1970 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1971 (player->streamer) &&
1972 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1973 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1974 GstQuery *query = NULL;
1975 gboolean busy = FALSE;
1978 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1979 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1980 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1981 gst_query_parse_buffering_percent(query, &busy, &percent);
1982 gst_query_unref(query);
1984 LOGD("buffered percent(%s): %d\n",
1985 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1989 __mmplayer_handle_buffering_playback(player);
1992 player->seek_state = MMPLAYER_SEEK_COMPLETED;
2001 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
2003 mm_player_t* player = (mm_player_t*)(data);
2005 MMPLAYER_RETURN_IF_FAIL(player);
2006 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2008 switch (GST_MESSAGE_TYPE(msg)) {
2009 case GST_MESSAGE_UNKNOWN:
2010 LOGD("unknown message received\n");
2013 case GST_MESSAGE_EOS:
2014 LOGD("GST_MESSAGE_EOS received");
2015 __mmplayer_gst_handle_eos_message(player, msg);
2018 case GST_MESSAGE_ERROR:
2019 __mmplayer_gst_handle_error_message(player, msg);
2022 case GST_MESSAGE_WARNING:
2025 GError* error = NULL;
2027 gst_message_parse_warning(msg, &error, &debug);
2029 LOGD("warning : %s\n", error->message);
2030 LOGD("debug : %s\n", debug);
2032 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2034 MMPLAYER_FREEIF(debug);
2035 g_error_free(error);
2039 case GST_MESSAGE_TAG:
2041 LOGD("GST_MESSAGE_TAG\n");
2042 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2043 LOGW("failed to extract tags from gstmessage\n");
2047 case GST_MESSAGE_BUFFERING:
2048 __mmplayer_gst_handle_buffering_message(player, msg);
2051 case GST_MESSAGE_STATE_CHANGED:
2052 __mmplayer_gst_handle_state_message(player, msg);
2055 case GST_MESSAGE_CLOCK_LOST:
2057 GstClock *clock = NULL;
2058 gboolean need_new_clock = FALSE;
2060 gst_message_parse_clock_lost(msg, &clock);
2061 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2063 if (!player->videodec_linked)
2064 need_new_clock = TRUE;
2065 else if (!player->ini.use_system_clock)
2066 need_new_clock = TRUE;
2068 if (need_new_clock) {
2069 LOGD("Provide clock is TRUE, do pause->resume\n");
2070 __mmplayer_gst_pause(player, FALSE);
2071 __mmplayer_gst_resume(player, FALSE);
2076 case GST_MESSAGE_NEW_CLOCK:
2078 GstClock *clock = NULL;
2079 gst_message_parse_new_clock(msg, &clock);
2080 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2084 case GST_MESSAGE_ELEMENT:
2085 __mmplayer_gst_handle_element_message(player, msg);
2088 case GST_MESSAGE_DURATION_CHANGED:
2090 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2091 if (!__mmplayer_gst_handle_duration(player, msg))
2092 LOGW("failed to update duration");
2096 case GST_MESSAGE_ASYNC_START:
2097 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2100 case GST_MESSAGE_ASYNC_DONE:
2101 __mmplayer_gst_handle_async_done_message(player, msg);
2104 #if 0 /* delete unnecessary logs */
2105 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2106 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2107 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2108 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2109 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2110 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2111 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2112 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2113 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2114 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2115 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2116 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2117 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2118 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2119 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2126 /* should not call 'gst_message_unref(msg)' */
2130 static GstBusSyncReply
2131 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2133 mm_player_t *player = (mm_player_t *)data;
2134 GstBusSyncReply reply = GST_BUS_DROP;
2136 if (!(player->pipeline && player->pipeline->mainbin)) {
2137 LOGE("player pipeline handle is null");
2138 return GST_BUS_PASS;
2141 if (!__mmplayer_gst_check_useful_message(player, message)) {
2142 gst_message_unref(message);
2143 return GST_BUS_DROP;
2146 switch (GST_MESSAGE_TYPE(message)) {
2147 case GST_MESSAGE_STATE_CHANGED:
2148 /* post directly for fast launch */
2149 if (player->sync_handler) {
2150 __mmplayer_gst_bus_msg_callback(message, player);
2151 reply = GST_BUS_DROP;
2153 reply = GST_BUS_PASS;
2155 case GST_MESSAGE_TAG:
2156 __mmplayer_gst_extract_tag_from_msg(player, message);
2160 GstTagList *tags = NULL;
2162 gst_message_parse_tag(message, &tags);
2164 LOGE("TAGS received from element \"%s\".\n",
2165 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2167 gst_tag_list_foreach(tags, print_tag, NULL);
2168 gst_tag_list_free(tags);
2176 case GST_MESSAGE_DURATION_CHANGED:
2177 __mmplayer_gst_handle_duration(player, message);
2179 case GST_MESSAGE_ASYNC_DONE:
2180 /* NOTE:Don't call gst_callback directly
2181 * because previous frame can be showed even though this message is received for seek.
2184 reply = GST_BUS_PASS;
2188 if (reply == GST_BUS_DROP)
2189 gst_message_unref(message);
2195 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2197 GstElement *appsrc = element;
2198 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2199 GstBuffer *buffer = NULL;
2200 GstFlowReturn ret = GST_FLOW_OK;
2203 MMPLAYER_RETURN_IF_FAIL(element);
2204 MMPLAYER_RETURN_IF_FAIL(buf);
2206 buffer = gst_buffer_new();
2208 if (buf->offset < 0 || buf->len < 0) {
2209 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2213 if (buf->offset >= buf->len) {
2214 LOGD("call eos appsrc");
2215 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2219 if (buf->len - buf->offset < size)
2220 len = buf->len - buf->offset;
2222 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2223 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2224 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2226 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2227 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2233 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2235 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2237 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2239 buf->offset = (int)size;
2245 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2247 mm_player_t *player = (mm_player_t*)user_data;
2248 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2249 guint64 current_level_bytes = 0;
2251 MMPLAYER_RETURN_IF_FAIL(player);
2253 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2254 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2255 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2256 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2257 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2258 type = MM_PLAYER_STREAM_TYPE_TEXT;
2260 LOGE("can not enter here");
2264 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2266 LOGI("type: %d, level: %llu", type, current_level_bytes);
2268 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2269 if (player->media_stream_buffer_status_cb[type])
2270 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2271 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2275 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2277 mm_player_t *player = (mm_player_t*)user_data;
2278 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2279 guint64 current_level_bytes = 0;
2281 MMPLAYER_RETURN_IF_FAIL(player);
2283 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2284 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2285 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2286 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2287 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2288 type = MM_PLAYER_STREAM_TYPE_TEXT;
2290 LOGE("can not enter here");
2294 LOGI("type: %d, buffer is full", type);
2296 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2298 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2300 if (player->media_stream_buffer_status_cb[type])
2301 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2303 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2307 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2309 mm_player_t *player = (mm_player_t*)user_data;
2310 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2312 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2314 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2315 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2316 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2317 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2318 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2319 type = MM_PLAYER_STREAM_TYPE_TEXT;
2321 LOGE("can not enter here");
2325 LOGD("type: %d, pos: %llu", type, position);
2326 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2328 if (player->media_stream_seek_data_cb[type])
2329 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2330 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2336 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2338 #define MAX_LEN_NAME 20
2340 gboolean ret = FALSE;
2341 GstPad *sinkpad = NULL;
2342 gchar *prefix = NULL;
2343 gchar dec_name[MAX_LEN_NAME] = {0};
2344 enum MainElementID elem_id = MMPLAYER_M_NUM;
2346 MMPlayerGstElement *mainbin = NULL;
2347 GstElement *decodebin = NULL;
2348 GstCaps *dec_caps = NULL;
2352 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2354 player->pipeline->mainbin, FALSE);
2355 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2357 mainbin = player->pipeline->mainbin;
2359 case MM_PLAYER_STREAM_TYPE_AUDIO:
2361 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2363 case MM_PLAYER_STREAM_TYPE_VIDEO:
2365 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2368 LOGE("invalid type %d", type);
2372 if (mainbin[elem_id].gst) {
2373 LOGE("elem(%d) is already created", elem_id);
2377 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2379 /* create decodebin */
2380 decodebin = gst_element_factory_make("decodebin", dec_name);
2382 LOGE("failed to create %s", dec_name);
2386 mainbin[elem_id].id = elem_id;
2387 mainbin[elem_id].gst = decodebin;
2389 /* raw pad handling signal */
2390 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2391 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2393 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2394 before looking for any elements that can handle that stream.*/
2395 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2396 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2398 /* This signal is emitted when a element is added to the bin.*/
2399 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2400 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2402 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2403 LOGE("failed to add new decodebin");
2407 dec_caps = gst_pad_query_caps(srcpad, NULL);
2409 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2410 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2411 gst_caps_unref(dec_caps);
2414 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2416 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2417 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2420 gst_object_unref(GST_OBJECT(sinkpad));
2422 gst_element_sync_state_with_parent(decodebin);
2428 gst_object_unref(GST_OBJECT(sinkpad));
2430 if (mainbin[elem_id].gst) {
2431 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2432 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2433 gst_object_unref(mainbin[elem_id].gst);
2434 mainbin[elem_id].gst = NULL;
2442 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2444 #define MAX_LEN_NAME 20
2445 MMPlayerGstElement *mainbin = NULL;
2446 gchar *prefix = NULL;
2447 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2449 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2450 GstElement *src = NULL, *queue = NULL;
2451 GstPad *srcpad = NULL;
2454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2455 player->pipeline->mainbin, FALSE);
2457 mainbin = player->pipeline->mainbin;
2459 LOGD("type(%d) path is creating", type);
2461 case MM_PLAYER_STREAM_TYPE_AUDIO:
2463 if (mainbin[MMPLAYER_M_SRC].gst)
2464 src_id = MMPLAYER_M_2ND_SRC;
2466 src_id = MMPLAYER_M_SRC;
2467 queue_id = MMPLAYER_M_A_BUFFER;
2469 case MM_PLAYER_STREAM_TYPE_VIDEO:
2471 src_id = MMPLAYER_M_SRC;
2472 queue_id = MMPLAYER_M_V_BUFFER;
2474 case MM_PLAYER_STREAM_TYPE_TEXT:
2475 prefix = "subtitle";
2476 src_id = MMPLAYER_M_SUBSRC;
2477 queue_id = MMPLAYER_M_S_BUFFER;
2480 LOGE("invalid type %d", type);
2484 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2485 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2488 src = gst_element_factory_make("appsrc", src_name);
2490 LOGF("failed to create %s", src_name);
2494 mainbin[src_id].id = src_id;
2495 mainbin[src_id].gst = src;
2497 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2498 "caps", caps, NULL);
2500 /* size of many video frames are larger than default blocksize as 4096 */
2501 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2502 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2504 if (player->media_stream_buffer_max_size[type] > 0)
2505 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2507 if (player->media_stream_buffer_min_percent[type] > 0)
2508 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2510 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2511 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2513 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2514 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2515 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2516 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2517 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2518 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2521 queue = gst_element_factory_make("queue2", queue_name);
2523 LOGE("failed to create %s", queue_name);
2526 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2528 mainbin[queue_id].id = queue_id;
2529 mainbin[queue_id].gst = queue;
2531 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2532 LOGE("failed to add src");
2536 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2537 LOGE("failed to add queue");
2541 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2542 LOGE("failed to link src and queue");
2546 /* create decoder */
2547 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2549 LOGE("failed to get srcpad of queue");
2553 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2554 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2556 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2557 LOGE("failed to create decoder");
2558 gst_object_unref(GST_OBJECT(srcpad));
2562 gst_object_unref(GST_OBJECT(srcpad));
2566 if (mainbin[src_id].gst) {
2567 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2568 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2569 gst_object_unref(mainbin[src_id].gst);
2570 mainbin[src_id].gst = NULL;
2573 if (mainbin[queue_id].gst) {
2574 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2575 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2576 gst_object_unref(mainbin[queue_id].gst);
2577 mainbin[queue_id].gst = NULL;
2584 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2586 GstPad *sinkpad = NULL;
2587 GstCaps* caps = NULL;
2588 GstElement* new_element = NULL;
2589 GstStructure* str = NULL;
2590 const gchar* name = NULL;
2592 mm_player_t* player = (mm_player_t*) data;
2596 MMPLAYER_RETURN_IF_FAIL(element && pad);
2597 MMPLAYER_RETURN_IF_FAIL(player &&
2599 player->pipeline->mainbin);
2602 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2603 * num_dynamic_pad will decreased after creating a sinkbin.
2605 player->num_dynamic_pad++;
2606 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2608 caps = gst_pad_query_caps(pad, NULL);
2610 MMPLAYER_CHECK_NULL(caps);
2612 /* clear previous result*/
2613 player->have_dynamic_pad = FALSE;
2615 str = gst_caps_get_structure(caps, 0);
2618 LOGE("cannot get structure from caps.\n");
2622 name = gst_structure_get_name(str);
2624 LOGE("cannot get mimetype from structure.\n");
2628 if (strstr(name, "video")) {
2630 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2632 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2633 if (player->v_stream_caps) {
2634 gst_caps_unref(player->v_stream_caps);
2635 player->v_stream_caps = NULL;
2638 new_element = gst_element_factory_make("fakesink", NULL);
2639 player->num_dynamic_pad--;
2644 /* clear previous result*/
2645 player->have_dynamic_pad = FALSE;
2647 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2648 LOGE("failed to autoplug for caps");
2652 /* check if there's dynamic pad*/
2653 if (player->have_dynamic_pad) {
2654 LOGE("using pad caps assums there's no dynamic pad !\n");
2658 gst_caps_unref(caps);
2663 /* excute new_element if created*/
2665 LOGD("adding new element to pipeline\n");
2667 /* set state to READY before add to bin */
2668 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2670 /* add new element to the pipeline */
2671 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2672 LOGE("failed to add autoplug element to bin\n");
2676 /* get pad from element */
2677 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2679 LOGE("failed to get sinkpad from autoplug element\n");
2684 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2685 LOGE("failed to link autoplug element\n");
2689 gst_object_unref(sinkpad);
2692 /* run. setting PLAYING here since streamming source is live source */
2693 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2697 gst_caps_unref(caps);
2703 STATE_CHANGE_FAILED:
2705 /* FIXIT : take care if new_element has already added to pipeline */
2707 gst_object_unref(GST_OBJECT(new_element));
2710 gst_object_unref(GST_OBJECT(sinkpad));
2713 gst_caps_unref(caps);
2715 /* FIXIT : how to inform this error to MSL ????? */
2716 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2717 * then post an error to application
2722 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2724 mm_player_t* player = (mm_player_t*) data;
2728 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2729 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2730 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2731 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2733 * [1] audio and video will be dumped with filesink.
2734 * [2] autoplugging is done by just using pad caps.
2735 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2736 * and the video will be dumped via filesink.
2738 if (player->num_dynamic_pad == 0) {
2739 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2741 if (!__mmplayer_gst_remove_fakesink(player,
2742 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2743 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2744 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2745 * source element are not same. To overcome this situation, this function will called
2746 * several places and several times. Therefore, this is not an error case.
2751 /* create dot before error-return. for debugging */
2752 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2754 player->no_more_pad = TRUE;
2760 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2762 GstElement* element = NULL;
2763 gchar *user_agent = NULL;
2764 MMHandleType attrs = 0;
2767 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2769 /* get profile attribute */
2770 attrs = MMPLAYER_GET_ATTRS(player);
2772 LOGE("failed to get content attribute");
2776 element = gst_element_factory_make("rtspsrc", "rtsp source");
2778 LOGE("failed to create rtspsrc element");
2783 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2785 SECURE_LOGD("user_agent : %s", user_agent);
2787 /* setting property to streaming source */
2788 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2790 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2792 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2793 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2794 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2795 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2802 __mmplayer_gst_make_http_src(mm_player_t* player)
2804 GstElement* element = NULL;
2805 MMHandleType attrs = 0;
2806 gchar *user_agent, *cookies, **cookie_list;
2807 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2808 user_agent = cookies = NULL;
2812 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2814 /* get profile attribute */
2815 attrs = MMPLAYER_GET_ATTRS(player);
2817 LOGE("failed to get content attribute");
2821 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2823 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2825 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2830 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2831 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2833 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2834 http_timeout = player->ini.http_timeout;
2837 SECURE_LOGD("location : %s", player->profile.uri);
2838 SECURE_LOGD("cookies : %s", cookies);
2839 SECURE_LOGD("user_agent : %s", user_agent);
2840 LOGD("timeout : %d", http_timeout);
2842 /* setting property to streaming source */
2843 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2844 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2846 /* parsing cookies */
2847 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2848 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2849 g_strfreev(cookie_list);
2853 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2855 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2856 LOGW("[DASH] this is still experimental feature");
2863 __mmplayer_gst_make_file_src(mm_player_t* player)
2865 GstElement* element = NULL;
2868 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2870 LOGD("using filesrc for 'file://' handler");
2871 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2872 LOGE("failed to get storage info");
2876 element = gst_element_factory_make("filesrc", "source");
2878 LOGE("failed to create filesrc");
2882 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2888 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2890 mm_player_t *player = (mm_player_t *) data;
2892 g_return_val_if_fail(player, FALSE);
2893 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2895 gst_message_ref(msg);
2897 g_mutex_lock(&player->bus_msg_q_lock);
2898 g_queue_push_tail(player->bus_msg_q, msg);
2899 g_mutex_unlock(&player->bus_msg_q_lock);
2901 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2902 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2903 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2907 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2909 mm_player_t *player = (mm_player_t*)(data);
2910 GstMessage *msg = NULL;
2914 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2916 player->pipeline->mainbin &&
2917 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2920 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2922 LOGE("cannot get BUS from the pipeline");
2926 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2928 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2929 while (!player->bus_msg_thread_exit) {
2930 g_mutex_lock(&player->bus_msg_q_lock);
2931 msg = g_queue_pop_head(player->bus_msg_q);
2932 g_mutex_unlock(&player->bus_msg_q_lock);
2934 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2937 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2938 /* handle the gst msg */
2939 __mmplayer_gst_bus_msg_callback(msg, player);
2940 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2941 gst_message_unref(msg);
2944 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2945 gst_object_unref(GST_OBJECT(bus));
2952 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2954 gint64 dur_nsec = 0;
2957 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2959 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2960 return MM_ERROR_NONE;
2962 /* NOTE : duration cannot be zero except live streaming.
2963 * Since some element could have some timing problemn with quering duration, try again.
2965 if (player->duration == 0) {
2966 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2967 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2968 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2969 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2970 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2971 player->pending_seek.is_pending = TRUE;
2972 player->pending_seek.pos = position;
2973 player->seek_state = MMPLAYER_SEEK_NONE;
2974 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2975 return MM_ERROR_PLAYER_NO_OP;
2977 player->seek_state = MMPLAYER_SEEK_NONE;
2978 return MM_ERROR_PLAYER_SEEK;
2981 player->duration = dur_nsec;
2984 if (player->duration > 0 && player->duration < position) {
2985 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2986 return MM_ERROR_INVALID_ARGUMENT;
2990 return MM_ERROR_NONE;
2994 __mmplayer_gst_check_seekable(mm_player_t* player)
2996 GstQuery *query = NULL;
2997 gboolean seekable = FALSE;
2999 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3003 query = gst_query_new_seeking(GST_FORMAT_TIME);
3004 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3005 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3006 gst_query_unref(query);
3009 LOGW("non-seekable content");
3010 player->seek_state = MMPLAYER_SEEK_NONE;
3014 LOGW("failed to get seeking query");
3015 gst_query_unref(query); /* keep seeking operation */
3026 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
3028 GstState element_state = GST_STATE_VOID_PENDING;
3029 GstState element_pending_state = GST_STATE_VOID_PENDING;
3030 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3034 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3035 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3037 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3040 ret = gst_element_set_state(element, state);
3042 if (ret == GST_STATE_CHANGE_FAILURE) {
3043 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3045 /* dump state of all element */
3046 __mmplayer_dump_pipeline_state(player);
3048 return MM_ERROR_PLAYER_INTERNAL;
3051 /* return here so state transition to be done in async mode */
3053 LOGD("async state transition. not waiting for state complete.\n");
3054 return MM_ERROR_NONE;
3057 /* wait for state transition */
3058 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3060 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3061 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3062 GST_ELEMENT_NAME(element),
3063 gst_element_state_get_name(state), timeout);
3065 LOGE(" [%s] state : %s pending : %s \n",
3066 GST_ELEMENT_NAME(element),
3067 gst_element_state_get_name(element_state),
3068 gst_element_state_get_name(element_pending_state));
3070 /* dump state of all element */
3071 __mmplayer_dump_pipeline_state(player);
3073 return MM_ERROR_PLAYER_INTERNAL;
3076 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3080 return MM_ERROR_NONE;
3083 int __mmplayer_gst_start(mm_player_t* player)
3085 int ret = MM_ERROR_NONE;
3086 gboolean async = FALSE;
3090 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3092 /* NOTE : if SetPosition was called before Start. do it now */
3093 /* streaming doesn't support it. so it should be always sync */
3094 /* !!create one more api to check if there is pending seek rather than checking variables */
3095 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3096 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3097 ret = __mmplayer_gst_pause(player, FALSE);
3098 if (ret != MM_ERROR_NONE) {
3099 LOGE("failed to set state to PAUSED for pending seek");
3103 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3104 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3105 LOGW("failed to seek pending postion. starting from the begin of content");
3108 LOGD("current state before doing transition");
3109 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3110 MMPLAYER_PRINT_STATE(player);
3112 /* set pipeline state to PLAYING */
3113 ret = __mmplayer_gst_set_state(player,
3114 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3116 if (ret == MM_ERROR_NONE) {
3117 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3119 LOGE("failed to set state to PLAYING");
3123 /* generating debug info before returning error */
3124 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3131 int __mmplayer_gst_stop(mm_player_t* player)
3133 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3134 MMHandleType attrs = 0;
3135 gboolean rewind = FALSE;
3137 int ret = MM_ERROR_NONE;
3141 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3142 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3144 LOGD("current state before doing transition");
3145 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3146 MMPLAYER_PRINT_STATE(player);
3148 attrs = MMPLAYER_GET_ATTRS(player);
3150 LOGE("cannot get content attribute\n");
3151 return MM_ERROR_PLAYER_INTERNAL;
3154 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3155 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3157 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3158 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3161 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3162 /* disable the async state transition because there could be no data in the pipeline */
3163 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3167 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3169 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3170 /* enable the async state transition as default operation */
3171 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3174 /* return if set_state has failed */
3175 if (ret != MM_ERROR_NONE) {
3176 LOGE("failed to set state.\n");
3182 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3183 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3184 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3185 LOGW("failed to rewind\n");
3186 ret = MM_ERROR_PLAYER_SEEK;
3191 player->sent_bos = FALSE;
3193 if (player->es_player_push_mode) //for cloudgame
3196 /* wait for seek to complete */
3197 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3198 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3199 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3201 LOGE("fail to stop player.\n");
3202 ret = MM_ERROR_PLAYER_INTERNAL;
3203 __mmplayer_dump_pipeline_state(player);
3206 /* generate dot file if enabled */
3207 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3214 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3216 int ret = MM_ERROR_NONE;
3220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3221 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3223 LOGD("current state before doing transition");
3224 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3225 MMPLAYER_PRINT_STATE(player);
3227 /* set pipeline status to PAUSED */
3228 ret = __mmplayer_gst_set_state(player,
3229 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3231 if (FALSE == async) {
3232 if (ret != MM_ERROR_NONE) {
3233 GstMessage *msg = NULL;
3234 GTimer *timer = NULL;
3235 gdouble MAX_TIMEOUT_SEC = 3;
3237 LOGE("failed to set state to PAUSED");
3239 if (!player->bus_watcher) {
3240 LOGE("there is no bus msg thread. pipeline is shutting down.");
3244 if (player->msg_posted) {
3245 LOGE("error msg is already posted.");
3249 timer = g_timer_new();
3250 g_timer_start(timer);
3252 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3255 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3257 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3258 GError *error = NULL;
3260 /* parse error code */
3261 gst_message_parse_error(msg, &error, NULL);
3263 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3264 /* Note : the streaming error from the streaming source is handled
3265 * using __mmplayer_handle_streaming_error.
3267 __mmplayer_handle_streaming_error(player, msg);
3270 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3272 if (error->domain == GST_STREAM_ERROR)
3273 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3274 else if (error->domain == GST_RESOURCE_ERROR)
3275 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3276 else if (error->domain == GST_LIBRARY_ERROR)
3277 ret = __mmplayer_gst_handle_library_error(player, error->code);
3278 else if (error->domain == GST_CORE_ERROR)
3279 ret = __mmplayer_gst_handle_core_error(player, error->code);
3281 g_error_free(error);
3283 player->msg_posted = TRUE;
3285 gst_message_unref(msg);
3287 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3289 gst_object_unref(bus);
3290 g_timer_stop(timer);
3291 g_timer_destroy(timer);
3295 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3296 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3298 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3301 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3305 /* generate dot file before returning error */
3306 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3313 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3315 int ret = MM_ERROR_NONE;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3321 MM_ERROR_PLAYER_NOT_INITIALIZED);
3323 LOGD("current state before doing transition");
3324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3325 MMPLAYER_PRINT_STATE(player);
3328 LOGD("do async state transition to PLAYING");
3330 /* set pipeline state to PLAYING */
3331 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3333 ret = __mmplayer_gst_set_state(player,
3334 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3335 if (ret != MM_ERROR_NONE) {
3336 LOGE("failed to set state to PLAYING");
3340 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3344 /* generate dot file */
3345 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3352 /* sending event to one of sinkelements */
3354 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3356 GstEvent * event2 = NULL;
3357 GList *sinks = NULL;
3358 gboolean res = FALSE;
3361 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3362 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3364 /* While adding subtitles in live feeds seek is getting called.
3365 Adding defensive check in framework layer.*/
3366 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3367 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3368 LOGE("Should not send seek event during live playback");
3373 if (player->play_subtitle)
3374 event2 = gst_event_copy((const GstEvent *)event);
3376 sinks = player->sink_elements;
3378 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3380 if (GST_IS_ELEMENT(sink)) {
3381 /* keep ref to the event */
3382 gst_event_ref(event);
3384 if ((res = gst_element_send_event(sink, event))) {
3385 LOGD("sending event[%s] to sink element [%s] success!\n",
3386 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3388 /* rtsp case, asyn_done is not called after seek during pause state */
3389 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3390 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3391 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3392 LOGD("RTSP seek completed, after pause state..\n");
3393 player->seek_state = MMPLAYER_SEEK_NONE;
3394 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3400 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3401 sinks = g_list_next(sinks);
3408 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3409 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3412 sinks = g_list_next(sinks);
3415 /* Note : Textbin is not linked to the video or audio bin.
3416 * It needs to send the event to the text sink seperatelly.
3418 if (player->play_subtitle && player->pipeline) {
3419 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3421 if (GST_IS_ELEMENT(text_sink)) {
3422 /* keep ref to the event */
3423 gst_event_ref(event2);
3425 if ((res = gst_element_send_event(text_sink, event2)))
3426 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3427 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3429 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3430 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3432 gst_event_unref(event2);
3436 gst_event_unref(event);
3444 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3445 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3446 gint64 cur, GstSeekType stop_type, gint64 stop)
3448 GstEvent* event = NULL;
3449 gboolean result = FALSE;
3453 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3455 if (player->pipeline && player->pipeline->textbin)
3456 __mmplayer_drop_subtitle(player, FALSE);
3458 event = gst_event_new_seek(rate, format, flags, cur_type,
3459 cur, stop_type, stop);
3461 result = __mmplayer_gst_send_event_to_sink(player, event);
3469 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3471 int ret = MM_ERROR_NONE;
3472 gint64 pos_nsec = 0;
3473 gboolean accurated = FALSE;
3474 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3477 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3478 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3480 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3481 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3484 ret = __mmplayer_gst_check_duration(player, position);
3485 if (ret != MM_ERROR_NONE) {
3486 LOGE("failed to check duration 0x%X", ret);
3487 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3490 if (!__mmplayer_gst_check_seekable(player))
3491 return MM_ERROR_PLAYER_NO_OP;
3493 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3494 position, player->playback_rate, player->duration);
3496 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3497 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3498 This causes problem is position calculation during normal pause resume scenarios also.
3499 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3500 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3501 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3502 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3503 LOGW("getting current position failed in seek");
3505 player->last_position = pos_nsec;
3506 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3509 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3510 LOGD("not completed seek");
3511 return MM_ERROR_PLAYER_DOING_SEEK;
3514 if (!internal_called)
3515 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3517 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3518 that's why set position through property. */
3519 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3520 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3521 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3522 (!player->videodec_linked) && (!player->audiodec_linked)) {
3524 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3525 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3527 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3528 player->seek_state = MMPLAYER_SEEK_NONE;
3529 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3531 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3533 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3535 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3537 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3538 GST_FORMAT_TIME, seek_flags,
3539 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3540 LOGE("failed to set position");
3545 /* NOTE : store last seeking point to overcome some bad operation
3546 * (returning zero when getting current position) of some elements
3548 player->last_position = position;
3550 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3551 if (player->playback_rate > 1.0)
3552 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3554 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3555 LOGD("buffering should be reset after seeking");
3556 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3557 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3561 return MM_ERROR_NONE;
3564 player->pending_seek.is_pending = TRUE;
3565 player->pending_seek.pos = position;
3567 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3568 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3569 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3570 player->pending_seek.pos);
3572 return MM_ERROR_NONE;
3575 player->seek_state = MMPLAYER_SEEK_NONE;
3576 return MM_ERROR_PLAYER_SEEK;
3580 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3582 #define TRICKPLAY_OFFSET GST_MSECOND
3584 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3585 gint64 pos_nsec = 0;
3586 gboolean ret = TRUE;
3588 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3589 MM_ERROR_PLAYER_NOT_INITIALIZED);
3591 current_state = MMPLAYER_CURRENT_STATE(player);
3593 /* NOTE : query position except paused state to overcome some bad operation
3594 * please refer to below comments in details
3596 if (current_state != MM_PLAYER_STATE_PAUSED)
3597 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3599 /* NOTE : get last point to overcome some bad operation of some elements
3600 *(returning zero when getting current position in paused state
3601 * and when failed to get postion during seeking
3603 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3604 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3606 if (player->playback_rate < 0.0)
3607 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3609 pos_nsec = player->last_position;
3612 pos_nsec = player->last_position;
3614 player->last_position = pos_nsec;
3616 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3619 if (player->duration > 0 && pos_nsec > player->duration)
3620 pos_nsec = player->duration;
3622 player->last_position = pos_nsec;
3625 *position = pos_nsec;
3627 return MM_ERROR_NONE;
3630 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3632 #define STREAMING_IS_FINISHED 0
3633 #define BUFFERING_MAX_PER 100
3634 #define DEFAULT_PER_VALUE -1
3635 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3637 MMPlayerGstElement *mainbin = NULL;
3638 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3639 gint64 buffered_total = 0;
3640 gint64 position = 0;
3641 gint buffered_sec = -1;
3642 GstBufferingMode mode = GST_BUFFERING_STREAM;
3643 gint64 content_size_time = player->duration;
3644 guint64 content_size_bytes = player->http_content_size;
3646 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3648 player->pipeline->mainbin,
3649 MM_ERROR_PLAYER_NOT_INITIALIZED);
3651 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3656 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3657 /* and rtsp is not ready yet. */
3658 LOGW("it's only used for http streaming case");
3659 return MM_ERROR_PLAYER_NO_OP;
3662 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3663 LOGW("Time format is not supported yet");
3664 return MM_ERROR_INVALID_ARGUMENT;
3667 if (content_size_time <= 0 || content_size_bytes <= 0) {
3668 LOGW("there is no content size");
3669 return MM_ERROR_NONE;
3672 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3673 LOGW("fail to get current position");
3674 return MM_ERROR_NONE;
3677 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3678 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3680 mainbin = player->pipeline->mainbin;
3681 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3683 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3684 GstQuery *query = NULL;
3685 gint byte_in_rate = 0, byte_out_rate = 0;
3686 gint64 estimated_total = 0;
3688 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3689 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3690 LOGW("fail to get buffering query from queue2");
3692 gst_query_unref(query);
3693 return MM_ERROR_NONE;
3696 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3697 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3699 if (mode == GST_BUFFERING_STREAM) {
3700 /* using only queue in case of push mode(ts / mp3) */
3701 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3702 GST_FORMAT_BYTES, &buffered_total)) {
3703 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3704 stop_per = 100 * buffered_total / content_size_bytes;
3707 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3709 guint num_of_ranges = 0;
3710 gint64 start_byte = 0, stop_byte = 0;
3712 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3713 if (estimated_total != STREAMING_IS_FINISHED) {
3714 /* buffered size info from queue2 */
3715 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3716 for (idx = 0; idx < num_of_ranges; idx++) {
3717 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3718 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3720 buffered_total += (stop_byte - start_byte);
3723 stop_per = BUFFERING_MAX_PER;
3725 gst_query_unref(query);
3728 if (stop_per == DEFAULT_PER_VALUE) {
3729 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3731 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3733 /* buffered size info from multiqueue */
3734 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3735 guint curr_size_bytes = 0;
3736 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3737 "curr-size-bytes", &curr_size_bytes, NULL);
3738 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3739 buffered_total += curr_size_bytes;
3742 if (avg_byterate > 0)
3743 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3744 else if (player->total_maximum_bitrate > 0)
3745 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3746 else if (player->total_bitrate > 0)
3747 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3749 if (buffered_sec >= 0)
3750 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3754 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3755 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3757 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3758 buffered_total, buffered_sec, *start_pos, *stop_pos);
3760 return MM_ERROR_NONE;
3763 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3765 GstElement* element = NULL;
3768 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3769 player->pipeline->mainbin, NULL);
3771 /* setup source for gapless play */
3772 switch (player->profile.uri_type) {
3774 case MM_PLAYER_URI_TYPE_FILE:
3775 element = __mmplayer_gst_make_file_src(player);
3777 case MM_PLAYER_URI_TYPE_URL_HTTP:
3778 element = __mmplayer_gst_make_http_src(player);
3781 LOGE("not support uri type %d", player->profile.uri_type);
3786 LOGE("failed to create source element");
3794 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3796 MMHandleType attrs = 0;
3799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3800 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3802 /* get profile attribute */
3803 attrs = MMPLAYER_GET_ATTRS(player);
3805 LOGE("failed to get content attribute");
3806 return MM_ERROR_PLAYER_INTERNAL;
3809 SECURE_LOGD("uri : %s", player->profile.uri);
3811 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3812 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3813 LOGE("failed to commit");
3815 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3816 return MM_ERROR_PLAYER_INTERNAL;
3818 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3819 return MM_ERROR_PLAYER_INTERNAL;
3821 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3822 return MM_ERROR_PLAYER_INTERNAL;
3825 return MM_ERROR_NONE;
3828 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3830 MMPlayerGstElement *mainbin = NULL;
3831 GstElement *pd_src = NULL;
3832 GstElement *pd_queue = NULL;
3833 GstElement *pd_decodebin = NULL;
3834 GList* element_bucket = NULL;
3835 MMHandleType attrs = 0;
3837 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3841 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3843 /* get profile attribute */
3844 attrs = MMPLAYER_GET_ATTRS(player);
3846 LOGE("failed to get content attribute");
3847 return MM_ERROR_PLAYER_INTERNAL;
3850 LOGD("http playback with progressive download : %d", player->pd_mode);
3852 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3853 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3854 MMPLAYER_FREEIF(player->pd_file_save_path);
3856 SECURE_LOGD("PD Location : %s", path);
3858 LOGE("filed to find pd location");
3859 return MM_ERROR_PLAYER_INTERNAL;
3862 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3863 LOGE("failed to get storage info");
3864 return MM_ERROR_PLAYER_INTERNAL;
3866 player->pd_file_save_path = g_strdup(path);
3869 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3871 LOGE("failed to create PD push source");
3872 return MM_ERROR_PLAYER_INTERNAL;
3875 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3876 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3878 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3880 mainbin = player->pipeline->mainbin;
3882 /* take source element */
3883 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3884 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3885 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3888 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3889 pd_queue = gst_element_factory_make("queue2", "queue2");
3891 LOGE("failed to create pd buffer element");
3896 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3897 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3898 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3900 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3902 player->streamer->is_pd_mode = TRUE;
3904 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3905 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3906 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3908 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3909 if (!pd_decodebin) {
3910 LOGE("failed to create decodebin");
3914 /* default size of mq in decodebin is 2M
3915 * but it can cause blocking issue during seeking depends on content. */
3916 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3918 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3919 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3921 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3923 /* add elements to pipeline */
3924 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3925 LOGE("failed to add elements to pipeline");
3929 /* linking elements in the bucket by added order. */
3930 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3931 LOGE("failed to link some elements");
3935 g_list_free(element_bucket);
3938 return MM_ERROR_NONE;
3941 MMPLAYER_FREEIF(player->pd_file_save_path);
3942 g_list_free(element_bucket);
3944 if (mainbin[MMPLAYER_M_SRC].gst)
3945 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3947 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3948 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3950 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3951 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3953 mainbin[MMPLAYER_M_SRC].gst = NULL;
3954 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3955 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3957 return MM_ERROR_PLAYER_INTERNAL;
3960 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3962 MMPlayerGstElement *mainbin = NULL;
3963 GstElement* src_elem = NULL;
3964 GstElement *autoplug_elem = NULL;
3965 GList* element_bucket = NULL;
3966 MMHandleType attrs = 0;
3967 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3970 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3971 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3973 /* get profile attribute */
3974 attrs = MMPLAYER_GET_ATTRS(player);
3976 LOGE("failed to get content attribute");
3977 return MM_ERROR_PLAYER_INTERNAL;
3980 LOGD("uri type %d", player->profile.uri_type);
3982 /* create source element */
3983 switch (player->profile.uri_type) {
3984 case MM_PLAYER_URI_TYPE_URL_RTSP:
3985 src_elem = __mmplayer_gst_make_rtsp_src(player);
3987 case MM_PLAYER_URI_TYPE_URL_HTTP:
3988 src_elem = __mmplayer_gst_make_http_src(player);
3990 case MM_PLAYER_URI_TYPE_FILE:
3991 src_elem = __mmplayer_gst_make_file_src(player);
3993 case MM_PLAYER_URI_TYPE_SS:
3995 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3996 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3998 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4002 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4003 LOGD("get timeout from ini");
4004 http_timeout = player->ini.http_timeout;
4007 /* setting property to streaming source */
4008 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4011 case MM_PLAYER_URI_TYPE_MEM:
4013 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4015 src_elem = gst_element_factory_make("appsrc", "mem-source");
4017 LOGE("failed to create appsrc element");
4021 g_object_set(src_elem, "stream-type", stream_type,
4022 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4024 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4025 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4026 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4027 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4031 LOGE("not support uri type");
4036 LOGE("failed to create source element");
4037 return MM_ERROR_PLAYER_INTERNAL;
4040 mainbin = player->pipeline->mainbin;
4042 /* take source element */
4043 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4045 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4046 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4047 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4049 /* create next element for auto-plugging */
4050 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4051 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4052 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4053 if (!autoplug_elem) {
4054 LOGE("failed to create typefind element");
4058 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4059 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4060 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4061 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4062 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4063 if (!autoplug_elem) {
4064 LOGE("failed to create decodebin");
4068 /* default size of mq in decodebin is 2M
4069 * but it can cause blocking issue during seeking depends on content. */
4070 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4073 if (autoplug_elem) {
4074 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4075 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4076 mainbin[autoplug_elem_id].gst = autoplug_elem;
4078 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4081 /* add elements to pipeline */
4082 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4083 LOGE("failed to add elements to pipeline");
4087 /* linking elements in the bucket by added order. */
4088 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4089 LOGE("failed to link some elements");
4093 /* FIXME: need to check whether this is required or not. */
4094 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4095 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4096 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4097 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4099 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4100 LOGE("failed to create fakesink");
4103 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4105 /* take ownership of fakesink. we are reusing it */
4106 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4108 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4109 LOGE("failed to add fakesink to bin");
4110 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4115 g_list_free(element_bucket);
4118 return MM_ERROR_NONE;
4121 g_list_free(element_bucket);
4123 if (mainbin[MMPLAYER_M_SRC].gst)
4124 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4126 if (mainbin[autoplug_elem_id].gst)
4127 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4129 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4130 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4132 mainbin[MMPLAYER_M_SRC].gst = NULL;
4133 mainbin[autoplug_elem_id].gst = NULL;
4134 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4136 return MM_ERROR_PLAYER_INTERNAL;
4139 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4142 MMPlayerGstElement *mainbin = NULL;
4145 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4146 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 mainbin = player->pipeline->mainbin;
4150 /* connect bus callback */
4151 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4153 LOGE("cannot get bus from pipeline");
4154 return MM_ERROR_PLAYER_INTERNAL;
4157 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4158 player->context.thread_default = g_main_context_get_thread_default();
4159 if (player->context.thread_default == NULL) {
4160 player->context.thread_default = g_main_context_default();
4161 LOGD("thread-default context is the global default context");
4163 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4165 /* set sync handler to get tag synchronously */
4166 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4167 gst_object_unref(GST_OBJECT(bus));
4169 /* create gst bus_msb_cb thread */
4170 g_mutex_init(&player->bus_msg_thread_mutex);
4171 g_cond_init(&player->bus_msg_thread_cond);
4172 player->bus_msg_thread_exit = FALSE;
4173 player->bus_msg_thread =
4174 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4175 if (!player->bus_msg_thread) {
4176 LOGE("failed to create gst BUS msg thread");
4177 g_mutex_clear(&player->bus_msg_thread_mutex);
4178 g_cond_clear(&player->bus_msg_thread_cond);
4179 return MM_ERROR_PLAYER_INTERNAL;
4183 return MM_ERROR_NONE;