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