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 <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
37 /*===========================================================================================
39 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
41 ========================================================================================== */
43 /*---------------------------------------------------------------------------
44 | GLOBAL CONSTANT DEFINITIONS: |
45 ---------------------------------------------------------------------------*/
47 /*---------------------------------------------------------------------------
48 | IMPORTED VARIABLE DECLARATIONS: |
49 ---------------------------------------------------------------------------*/
51 /*---------------------------------------------------------------------------
52 | IMPORTED FUNCTION DECLARATIONS: |
53 ---------------------------------------------------------------------------*/
55 /*---------------------------------------------------------------------------
57 ---------------------------------------------------------------------------*/
59 /*---------------------------------------------------------------------------
60 | LOCAL CONSTANT DEFINITIONS: |
61 ---------------------------------------------------------------------------*/
63 /*---------------------------------------------------------------------------
64 | LOCAL DATA TYPE DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | GLOBAL VARIABLE DEFINITIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | LOCAL VARIABLE DEFINITIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
76 | LOCAL FUNCTION PROTOTYPES: |
77 ---------------------------------------------------------------------------*/
79 /*===========================================================================================
81 | FUNCTION DEFINITIONS |
83 ========================================================================================== */
85 /* NOTE : decide gstreamer state whether there is some playable track or not. */
87 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
89 gchar *src_element_name = NULL;
90 GstElement *src_element = NULL;
91 GstElementFactory *factory = NULL;
92 const gchar* klass = NULL;
96 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
97 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
98 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
99 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
101 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
103 src_element = GST_ELEMENT_CAST(message->src);
107 src_element_name = GST_ELEMENT_NAME(src_element);
108 if (!src_element_name)
111 factory = gst_element_get_factory(src_element);
115 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
119 LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
120 error->code, error->message, src_element_name, klass);
122 /* check whether the error is posted from not-activated track or not */
123 if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
125 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
126 LOGD("current active pad index -%d", active_pad_index);
128 if (src_element_name) {
131 if (player->audio_decoders) {
132 GList *adec = player->audio_decoders;
133 for (; adec ; adec = g_list_next(adec)) {
134 gchar *name = adec->data;
136 LOGD("found audio decoder name = %s", name);
137 if (g_strrstr(name, src_element_name)) {
144 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
147 if (active_pad_index != msg_src_pos) {
148 LOGD("skip error because error is posted from no activated track");
149 return MM_ERROR_NONE;
153 switch (error->code) {
154 case GST_STREAM_ERROR_DECODE:
156 /* Demuxer can't parse one track because it's corrupted.
157 * So, the decoder for it is not linked.
158 * But, it has one playable track.
160 if (g_strrstr(klass, "Demux")) {
161 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
162 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
163 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
164 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
166 if (player->pipeline->audiobin) // PCM
167 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
169 goto CODEC_NOT_FOUND;
172 return MM_ERROR_PLAYER_INVALID_STREAM;
176 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
177 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
178 case GST_STREAM_ERROR_WRONG_TYPE:
180 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
181 LOGE("Not supported subtitle.");
182 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
184 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
187 case GST_STREAM_ERROR_FAILED:
189 /* Decoder Custom Message */
190 if (strstr(error->message, "ongoing")) {
191 if (strncasecmp(klass, "audio", 5)) {
192 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
193 LOGD("Video can keep playing.\n");
194 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
196 goto CODEC_NOT_FOUND;
198 } else if (strncasecmp(klass, "video", 5)) {
199 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
200 LOGD("Audio can keep playing.\n");
201 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
203 goto CODEC_NOT_FOUND;
206 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
210 case GST_STREAM_ERROR_DECRYPT:
211 case GST_STREAM_ERROR_DECRYPT_NOKEY:
213 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
215 if (strstr(error->message, "rights expired"))
216 return MM_ERROR_PLAYER_DRM_EXPIRED;
217 else if (strstr(error->message, "no rights"))
218 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219 else if (strstr(error->message, "has future rights"))
220 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221 else if (strstr(error->message, "opl violation"))
222 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
223 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
233 return MM_ERROR_PLAYER_INVALID_STREAM;
236 return MM_ERROR_PLAYER_INTERNAL;
239 LOGD("not found any available codec. Player should be destroyed.\n");
240 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
244 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
246 gint trans_err = MM_ERROR_NONE;
250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
253 case GST_CORE_ERROR_MISSING_PLUGIN:
254 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
255 case GST_CORE_ERROR_STATE_CHANGE:
256 case GST_CORE_ERROR_SEEK:
257 case GST_CORE_ERROR_NOT_IMPLEMENTED:
258 case GST_CORE_ERROR_FAILED:
259 case GST_CORE_ERROR_TOO_LAZY:
260 case GST_CORE_ERROR_PAD:
261 case GST_CORE_ERROR_THREAD:
262 case GST_CORE_ERROR_NEGOTIATION:
263 case GST_CORE_ERROR_EVENT:
264 case GST_CORE_ERROR_CAPS:
265 case GST_CORE_ERROR_TAG:
266 case GST_CORE_ERROR_CLOCK:
267 case GST_CORE_ERROR_DISABLED:
269 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
279 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
281 gint trans_err = MM_ERROR_NONE;
285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
288 case GST_LIBRARY_ERROR_FAILED:
289 case GST_LIBRARY_ERROR_TOO_LAZY:
290 case GST_LIBRARY_ERROR_INIT:
291 case GST_LIBRARY_ERROR_SHUTDOWN:
292 case GST_LIBRARY_ERROR_SETTINGS:
293 case GST_LIBRARY_ERROR_ENCODE:
295 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
305 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
307 gint trans_err = MM_ERROR_NONE;
311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
314 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
315 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
317 case GST_RESOURCE_ERROR_NOT_FOUND:
318 case GST_RESOURCE_ERROR_OPEN_READ:
319 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
320 || MMPLAYER_IS_RTSP_STREAMING(player)) {
321 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
324 case GST_RESOURCE_ERROR_READ:
325 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
326 || MMPLAYER_IS_RTSP_STREAMING(player)) {
327 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
329 } else if (message != NULL && message->src != NULL) {
330 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
331 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
333 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
334 path_type = MMPLAYER_PATH_VOD;
335 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
336 path_type = MMPLAYER_PATH_TEXT;
338 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
339 /* check storage state */
340 storage_get_state(player->storage_info[path_type].id, &storage_state);
341 player->storage_info[path_type].state = storage_state;
342 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
345 case GST_RESOURCE_ERROR_WRITE:
346 case GST_RESOURCE_ERROR_FAILED:
347 case GST_RESOURCE_ERROR_SEEK:
348 case GST_RESOURCE_ERROR_TOO_LAZY:
349 case GST_RESOURCE_ERROR_BUSY:
350 case GST_RESOURCE_ERROR_OPEN_WRITE:
351 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
352 case GST_RESOURCE_ERROR_CLOSE:
353 case GST_RESOURCE_ERROR_SYNC:
354 case GST_RESOURCE_ERROR_SETTINGS:
356 trans_err = MM_ERROR_PLAYER_INTERNAL;
366 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
368 gint trans_err = MM_ERROR_NONE;
372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
373 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
374 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
376 switch (error->code) {
377 case GST_STREAM_ERROR_FAILED:
378 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
379 case GST_STREAM_ERROR_DECODE:
380 case GST_STREAM_ERROR_WRONG_TYPE:
381 case GST_STREAM_ERROR_DECRYPT:
382 case GST_STREAM_ERROR_DECRYPT_NOKEY:
383 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
384 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
387 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
388 case GST_STREAM_ERROR_TOO_LAZY:
389 case GST_STREAM_ERROR_ENCODE:
390 case GST_STREAM_ERROR_DEMUX:
391 case GST_STREAM_ERROR_MUX:
392 case GST_STREAM_ERROR_FORMAT:
394 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
404 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
406 MMMessageParamType msg_param;
407 gchar *msg_src_element;
411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
412 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
414 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
416 memset(&msg_param, 0, sizeof(MMMessageParamType));
418 if (error->domain == GST_CORE_ERROR) {
419 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
420 } else if (error->domain == GST_LIBRARY_ERROR) {
421 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
422 } else if (error->domain == GST_RESOURCE_ERROR) {
423 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
424 } else if (error->domain == GST_STREAM_ERROR) {
425 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
427 LOGW("This error domain is not defined.\n");
429 /* we treat system error as an internal error */
430 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
434 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
436 msg_param.data = (void *) error->message;
438 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
439 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
443 if (msg_param.code == MM_ERROR_NONE)
446 /* skip error to avoid duplicated posting */
447 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
448 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
449 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
450 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
452 /* The error will be handled by mused.
453 * @ref _mmplayer_manage_external_storage_state() */
455 LOGW("storage is removed, skip error post");
459 /* post error to application */
460 if (!player->msg_posted) {
461 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
462 /* don't post more if one was sent already */
463 player->msg_posted = TRUE;
465 LOGD("skip error post because it's sent already.\n");
473 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
476 MMMessageParamType msg_param;
477 gchar *msg_src_element = NULL;
478 GstStructure *s = NULL;
480 gchar *error_string = NULL;
484 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
485 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
487 s = gst_structure_copy(gst_message_get_structure(message));
490 if (!gst_structure_get_uint(s, "error_id", &error_id))
491 error_id = MMPLAYER_STREAMING_ERROR_NONE;
494 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
495 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
497 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
498 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
500 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
501 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
503 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
504 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
506 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
507 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
509 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
510 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
512 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
515 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
518 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
521 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
524 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
527 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
530 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
533 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
536 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
539 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
542 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
545 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
548 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
551 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
554 case MMPLAYER_STREAMING_ERROR_GONE:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
557 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
560 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
563 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
566 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
569 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
572 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
575 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
578 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
581 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
584 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
587 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
590 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
593 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
596 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
599 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
602 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
605 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
608 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
611 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
614 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
617 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
620 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
623 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
626 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
631 gst_structure_free(s);
632 return MM_ERROR_PLAYER_STREAMING_FAIL;
636 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
638 msg_param.data = (void *) error_string;
641 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
643 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
644 msg_src_element, msg_param.code, (char*)msg_param.data);
647 /* post error to application */
648 if (!player->msg_posted) {
649 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
651 /* don't post more if one was sent already */
652 player->msg_posted = TRUE;
654 LOGD("skip error post because it's sent already.\n");
656 gst_structure_free(s);
657 g_free(error_string);
665 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
667 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
668 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
669 gst_tag_list_get_string(tags, "stitching_software",
670 &metadata->stitching_software);
671 gst_tag_list_get_string(tags, "projection_type",
672 &metadata->projection_type_string);
673 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
674 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
675 gst_tag_list_get_int(tags, "init_view_heading",
676 &metadata->init_view_heading);
677 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
678 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
679 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
680 gst_tag_list_get_int(tags, "full_pano_width_pixels",
681 &metadata->full_pano_width_pixels);
682 gst_tag_list_get_int(tags, "full_pano_height_pixels",
683 &metadata->full_pano_height_pixels);
684 gst_tag_list_get_int(tags, "cropped_area_image_width",
685 &metadata->cropped_area_image_width);
686 gst_tag_list_get_int(tags, "cropped_area_image_height",
687 &metadata->cropped_area_image_height);
688 gst_tag_list_get_int(tags, "cropped_area_left",
689 &metadata->cropped_area_left);
690 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
691 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
692 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
693 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
697 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
700 /* macro for better code readability */
701 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
702 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
703 if (string != NULL) { \
704 SECURE_LOGD("update tag string : %s\n", string); \
705 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
706 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
707 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
708 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
709 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
710 g_free(new_string); \
713 mm_attrs_set_string_by_name(attribute, playertag, string); \
720 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
722 GstSample *sample = NULL;\
723 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
724 GstMapInfo info = GST_MAP_INFO_INIT;\
725 buffer = gst_sample_get_buffer(sample);\
726 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
727 LOGD("failed to get image data from tag");\
728 gst_sample_unref(sample);\
731 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
732 MMPLAYER_FREEIF(player->album_art);\
733 player->album_art = (gchar *)g_malloc(info.size);\
734 if (player->album_art) {\
735 memcpy(player->album_art, info.data, info.size);\
736 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
737 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
738 msg_param.data = (void *)player->album_art;\
739 msg_param.size = info.size;\
740 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
741 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
744 gst_buffer_unmap(buffer, &info);\
745 gst_sample_unref(sample);\
749 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
751 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
754 gchar *tag_list_str = NULL; \
755 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
756 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
757 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
758 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
759 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
761 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
762 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
763 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
764 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
765 player->bitrate[track_type] = v_uint; \
766 player->total_bitrate = 0; \
767 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
768 player->total_bitrate += player->bitrate[i]; \
769 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
770 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
771 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
772 player->maximum_bitrate[track_type] = v_uint; \
773 player->total_maximum_bitrate = 0; \
774 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
775 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
776 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
777 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
779 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
782 g_free(tag_list_str); \
787 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
788 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
790 string = g_strdup_printf("%d", g_date_get_year(date));\
791 mm_attrs_set_string_by_name(attribute, playertag, string);\
792 SECURE_LOGD("metainfo year : %s\n", string);\
793 MMPLAYER_FREEIF(string);\
798 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
799 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
800 if (datetime != NULL) {\
801 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
802 mm_attrs_set_string_by_name(attribute, playertag, string);\
803 SECURE_LOGD("metainfo year : %s\n", string);\
804 MMPLAYER_FREEIF(string);\
805 gst_date_time_unref(datetime);\
809 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
810 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
812 /* FIXIT : don't know how to store date */\
818 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
821 /* FIXIT : don't know how to store date */\
828 GstTagList* tag_list = NULL;
830 MMHandleType attrs = 0;
835 GstDateTime *datetime = NULL;
837 GstBuffer *buffer = NULL;
839 MMMessageParamType msg_param = {0, };
841 /* currently not used. but those are needed for above macro */
842 //guint64 v_uint64 = 0;
843 //gdouble v_double = 0;
845 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
847 attrs = MMPLAYER_GET_ATTRS(player);
849 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
851 /* get tag list from gst message */
852 gst_message_parse_tag(msg, &tag_list);
854 /* store tags to player attributes */
855 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
856 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
857 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
858 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
859 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
860 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
861 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
862 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
863 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
864 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
865 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
866 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
867 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
868 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
869 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
870 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
871 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
872 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
873 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
874 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
875 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
876 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
877 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
878 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
879 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
880 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
882 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
885 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
886 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
887 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
888 MMPLAYER_UPDATE_TAG_LOCK(player);
889 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
890 MMPLAYER_UPDATE_TAG_UNLOCK(player);
891 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
892 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
897 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
898 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
901 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
902 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
903 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
905 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
906 if (player->video360_metadata.is_spherical == -1) {
907 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
908 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
909 player->video360_metadata.is_spherical);
910 if (player->video360_metadata.is_spherical == 1) {
911 LOGD("This is spherical content for 360 playback.");
912 player->is_content_spherical = TRUE;
914 LOGD("This is not spherical content");
915 player->is_content_spherical = FALSE;
918 if (player->video360_metadata.projection_type_string) {
919 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
920 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
922 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
923 player->is_content_spherical = player->is_video360_enabled = FALSE;
927 if (player->video360_metadata.stereo_mode_string) {
928 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
929 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
930 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
931 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
932 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
933 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
935 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
936 player->is_content_spherical = player->is_video360_enabled = FALSE;
942 if (mm_attrs_commit_all(attrs))
943 LOGE("failed to commit.\n");
945 gst_tag_list_free(tag_list);
950 /* if retval is FALSE, it will be dropped for perfomance. */
952 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
954 gboolean retval = FALSE;
956 if (!(player->pipeline && player->pipeline->mainbin)) {
957 LOGE("player pipeline handle is null");
961 switch (GST_MESSAGE_TYPE(message)) {
962 case GST_MESSAGE_TAG:
963 case GST_MESSAGE_EOS:
964 case GST_MESSAGE_ERROR:
965 case GST_MESSAGE_WARNING:
966 case GST_MESSAGE_CLOCK_LOST:
967 case GST_MESSAGE_NEW_CLOCK:
968 case GST_MESSAGE_ELEMENT:
969 case GST_MESSAGE_DURATION_CHANGED:
970 case GST_MESSAGE_ASYNC_START:
973 case GST_MESSAGE_ASYNC_DONE:
974 case GST_MESSAGE_STATE_CHANGED:
975 /* we only handle messages from pipeline */
976 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
981 case GST_MESSAGE_BUFFERING:
983 gint buffer_percent = 0;
986 gst_message_parse_buffering(message, &buffer_percent);
987 if (buffer_percent != MAX_BUFFER_PERCENT) {
988 LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
992 if (!MMPLAYER_CMD_TRYLOCK(player)) {
993 LOGW("can't get cmd lock, send msg to bus");
997 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
998 LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
999 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1002 MMPLAYER_CMD_UNLOCK(player);
1015 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1017 MMHandleType attrs = 0;
1018 guint64 data_size = 0;
1020 gint64 pos_nsec = 0;
1023 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1025 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1027 attrs = MMPLAYER_GET_ATTRS(player);
1029 LOGE("fail to get attributes.\n");
1033 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1034 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1036 if (stat(path, &sb) == 0)
1037 data_size = (guint64)sb.st_size;
1038 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1039 data_size = player->http_content_size;
1042 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1043 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1049 __mmplayer_handle_buffering_playback(mm_player_t* player)
1051 int ret = MM_ERROR_NONE;
1052 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1053 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1054 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1055 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1057 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1058 LOGW("do nothing for buffering msg\n");
1059 ret = MM_ERROR_PLAYER_INVALID_STATE;
1063 prev_state = MMPLAYER_PREV_STATE(player);
1064 current_state = MMPLAYER_CURRENT_STATE(player);
1065 target_state = MMPLAYER_TARGET_STATE(player);
1066 pending_state = MMPLAYER_PENDING_STATE(player);
1068 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1069 MMPLAYER_STATE_GET_NAME(prev_state),
1070 MMPLAYER_STATE_GET_NAME(current_state),
1071 MMPLAYER_STATE_GET_NAME(pending_state),
1072 MMPLAYER_STATE_GET_NAME(target_state),
1073 player->streamer->buffering_state);
1075 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1076 /* NOTE : if buffering has done, player has to go to target state. */
1077 switch (target_state) {
1078 case MM_PLAYER_STATE_PAUSED:
1080 switch (pending_state) {
1081 case MM_PLAYER_STATE_PLAYING:
1082 __mmplayer_gst_pause(player, TRUE);
1085 case MM_PLAYER_STATE_PAUSED:
1086 LOGD("player is already going to paused state, there is nothing to do.\n");
1089 case MM_PLAYER_STATE_NONE:
1090 case MM_PLAYER_STATE_NULL:
1091 case MM_PLAYER_STATE_READY:
1093 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1099 case MM_PLAYER_STATE_PLAYING:
1101 switch (pending_state) {
1102 case MM_PLAYER_STATE_NONE:
1104 if (current_state != MM_PLAYER_STATE_PLAYING)
1105 __mmplayer_gst_resume(player, TRUE);
1109 case MM_PLAYER_STATE_PAUSED:
1110 /* NOTE: It should be worked as asynchronously.
1111 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1113 if (current_state == MM_PLAYER_STATE_PLAYING) {
1114 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1115 * The current state should be changed to paused purposely to prevent state conflict.
1117 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1119 __mmplayer_gst_resume(player, TRUE);
1122 case MM_PLAYER_STATE_PLAYING:
1123 LOGD("player is already going to playing state, there is nothing to do.\n");
1126 case MM_PLAYER_STATE_NULL:
1127 case MM_PLAYER_STATE_READY:
1129 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1135 case MM_PLAYER_STATE_NULL:
1136 case MM_PLAYER_STATE_READY:
1137 case MM_PLAYER_STATE_NONE:
1139 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1143 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1144 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1146 switch (pending_state) {
1147 case MM_PLAYER_STATE_NONE:
1149 if (current_state != MM_PLAYER_STATE_PAUSED) {
1150 /* rtsp streaming pause makes rtsp server stop sending data. */
1151 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1152 LOGD("set pause state during buffering\n");
1153 __mmplayer_gst_pause(player, TRUE);
1159 case MM_PLAYER_STATE_PLAYING:
1160 /* rtsp streaming pause makes rtsp server stop sending data. */
1161 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1162 __mmplayer_gst_pause(player, TRUE);
1165 case MM_PLAYER_STATE_PAUSED:
1168 case MM_PLAYER_STATE_NULL:
1169 case MM_PLAYER_STATE_READY:
1171 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1180 static VariantData *
1181 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1183 VariantData *var_info = NULL;
1184 g_return_val_if_fail(self != NULL, NULL);
1186 var_info = g_new0(VariantData, 1);
1187 if (!var_info) return NULL;
1188 var_info->bandwidth = self->bandwidth;
1189 var_info->width = self->width;
1190 var_info->height = self->height;
1195 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1201 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1202 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1204 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1205 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1206 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1208 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1209 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1210 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1213 /* handling audio clip which has vbr. means duration is keep changing */
1214 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1223 __mmplayer_eos_timer_cb(gpointer u_data)
1225 mm_player_t* player = NULL;
1226 MMHandleType attrs = 0;
1229 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1231 player = (mm_player_t*) u_data;
1232 attrs = MMPLAYER_GET_ATTRS(player);
1234 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1238 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1239 if (ret_value != MM_ERROR_NONE)
1240 LOGE("seeking to 0 failed in repeat play");
1243 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1246 /* we are returning FALSE as we need only one posting */
1251 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1253 MMPLAYER_RETURN_IF_FAIL(player);
1255 /* post now if delay is zero */
1256 if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1257 LOGD("eos delay is zero. posting EOS now\n");
1258 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1260 if (player->audio_stream_render_cb)
1261 __mmplayer_cancel_eos_timer(player);
1266 /* cancel if existing */
1267 __mmplayer_cancel_eos_timer(player);
1269 /* init new timeout */
1270 /* NOTE : consider give high priority to this timer */
1271 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1273 player->eos_timer = g_timeout_add(delay_in_ms,
1274 __mmplayer_eos_timer_cb, player);
1276 player->context.global_default = g_main_context_default();
1277 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1279 /* check timer is valid. if not, send EOS now */
1280 if (player->eos_timer == 0) {
1281 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1282 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1286 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1288 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1289 int ret = MM_ERROR_NONE;
1293 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1295 if (!player->pending_seek.is_pending) {
1296 LOGD("pending seek is not reserved. nothing to do.\n");
1300 /* check player state if player could pending seek or not. */
1301 current_state = MMPLAYER_CURRENT_STATE(player);
1303 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1304 LOGW("try to pending seek in %s state, try next time. \n",
1305 MMPLAYER_STATE_GET_NAME(current_state));
1309 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1311 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1313 if (MM_ERROR_NONE != ret)
1314 LOGE("failed to seek pending postion. just keep staying current position.\n");
1316 player->pending_seek.is_pending = FALSE;
1324 __mmplayer_gst_set_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_set_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_set_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 && player->pipeline->textbin)
1399 __mmplayer_drop_subtitle(player, TRUE);
1401 if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1402 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1404 /* rewind if repeat count is greater then zero */
1405 /* get play count */
1406 attrs = MMPLAYER_GET_ATTRS(player);
1409 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1411 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1413 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1414 if (player->playback_rate < 0.0) {
1415 player->resumed_by_rewind = TRUE;
1416 _mmplayer_set_mute((MMHandleType)player, 0);
1417 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1420 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1423 player->sent_bos = FALSE;
1425 LOGD("do not post eos msg for repeating");
1430 if (player->pipeline)
1431 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1433 /* post eos message to application */
1434 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1436 /* reset last position */
1437 player->last_position = 0;
1444 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1446 GError *error = NULL;
1447 gchar* debug = NULL;
1451 /* generating debug info before returning error */
1452 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1454 /* get error code */
1455 gst_message_parse_error(msg, &error, &debug);
1457 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1458 /* Note : the streaming error from the streaming source is handled
1459 * using __mmplayer_handle_streaming_error.
1461 __mmplayer_handle_streaming_error(player, msg);
1463 /* dump state of all element */
1464 __mmplayer_dump_pipeline_state(player);
1466 /* traslate gst error code to msl error code. then post it
1467 * to application if needed
1469 __mmplayer_handle_gst_error(player, msg, error);
1472 LOGE("error debug : %s", debug);
1475 if (MMPLAYER_IS_HTTP_PD(player))
1476 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1478 MMPLAYER_FREEIF(debug);
1479 g_error_free(error);
1486 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1488 MMMessageParamType msg_param = {0, };
1489 int bRet = MM_ERROR_NONE;
1492 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1494 if (!MMPLAYER_IS_STREAMING(player)) {
1495 LOGW("this is not streaming playback.");
1499 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1500 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1501 /* skip the playback control by buffering msg while user request is handled. */
1504 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1506 gst_message_parse_buffering(msg, &per);
1507 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1509 msg_param.connection.buffering = per;
1510 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1514 MMPLAYER_CMD_LOCK(player);
1517 if (!player->streamer) {
1518 LOGW("Pipeline is shutting down");
1519 MMPLAYER_CMD_UNLOCK(player);
1523 /* ignore the remained buffering message till getting 100% msg */
1524 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1525 gint buffer_percent = 0;
1527 gst_message_parse_buffering(msg, &buffer_percent);
1529 if (buffer_percent == MAX_BUFFER_PERCENT) {
1530 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1531 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1533 MMPLAYER_CMD_UNLOCK(player);
1537 /* ignore the remained buffering message */
1538 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1539 gint buffer_percent = 0;
1541 gst_message_parse_buffering(msg, &buffer_percent);
1543 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1544 player->streamer->buffering_percent, buffer_percent);
1546 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1547 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1548 player->streamer->buffering_req.is_pre_buffering = FALSE;
1550 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1552 LOGD("interrupted buffering - ignored the remained buffering msg!");
1553 MMPLAYER_CMD_UNLOCK(player);
1558 __mmplayer_update_buffer_setting(player, msg);
1560 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1562 if (bRet == MM_ERROR_NONE) {
1563 msg_param.connection.buffering = player->streamer->buffering_percent;
1564 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1566 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1567 player->pending_resume &&
1568 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1570 player->is_external_subtitle_added_now = FALSE;
1571 player->pending_resume = FALSE;
1572 _mmplayer_resume((MMHandleType)player);
1575 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1576 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1578 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1579 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1580 player->seek_state = MMPLAYER_SEEK_NONE;
1581 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1582 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1583 /* Considering the async state trasition in case of RTSP.
1584 After getting state change gst msg, seek cmpleted msg will be posted. */
1585 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1589 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1590 if (!player->streamer) {
1591 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1592 MMPLAYER_CMD_UNLOCK(player);
1596 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1598 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1599 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1601 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1602 msg_param.connection.buffering = player->streamer->buffering_percent;
1603 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1605 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1608 msg_param.connection.buffering = player->streamer->buffering_percent;
1609 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1612 MMPLAYER_CMD_UNLOCK(player);
1620 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1622 MMPlayerGstElement *mainbin;
1623 const GValue *voldstate, *vnewstate, *vpending;
1624 GstState oldstate = GST_STATE_NULL;
1625 GstState newstate = GST_STATE_NULL;
1626 GstState pending = GST_STATE_NULL;
1629 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1631 mainbin = player->pipeline->mainbin;
1633 /* we only handle messages from pipeline */
1634 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1637 /* get state info from msg */
1638 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1639 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1640 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1642 if (!voldstate || !vnewstate) {
1643 LOGE("received msg has wrong format.");
1647 oldstate = (GstState)voldstate->data[0].v_int;
1648 newstate = (GstState)vnewstate->data[0].v_int;
1650 pending = (GstState)vpending->data[0].v_int;
1652 LOGD("state changed [%s] : %s ---> %s final : %s",
1653 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1654 gst_element_state_get_name((GstState)oldstate),
1655 gst_element_state_get_name((GstState)newstate),
1656 gst_element_state_get_name((GstState)pending));
1658 if (newstate == GST_STATE_PLAYING) {
1659 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1661 int retVal = MM_ERROR_NONE;
1662 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1664 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1666 if (MM_ERROR_NONE != retVal)
1667 LOGE("failed to seek pending postion. just keep staying current position.");
1669 player->pending_seek.is_pending = FALSE;
1673 if (oldstate == newstate) {
1674 LOGD("pipeline reports state transition to old state");
1679 case GST_STATE_PAUSED:
1681 gboolean prepare_async = FALSE;
1683 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1684 // managed prepare async case
1685 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1686 LOGD("checking prepare mode for async transition - %d", prepare_async);
1689 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1690 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1692 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1693 __mm_player_streaming_set_content_bitrate(player->streamer,
1694 player->total_maximum_bitrate, player->total_bitrate);
1696 if (player->pending_seek.is_pending) {
1697 LOGW("trying to do pending seek");
1698 MMPLAYER_CMD_LOCK(player);
1699 __mmplayer_gst_pending_seek(player);
1700 MMPLAYER_CMD_UNLOCK(player);
1706 case GST_STATE_PLAYING:
1708 if (MMPLAYER_IS_STREAMING(player)) {
1709 // managed prepare async case when buffering is completed
1710 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1711 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1712 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1713 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1715 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1717 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1718 if (player->streamer->buffering_percent < 100) {
1720 MMMessageParamType msg_param = {0, };
1721 LOGW("Posting Buffering Completed Message to Application !!!");
1723 msg_param.connection.buffering = 100;
1724 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1729 if (player->gapless.stream_changed) {
1730 __mmplayer_update_content_attrs(player, ATTR_ALL);
1731 player->gapless.stream_changed = FALSE;
1734 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1735 player->seek_state = MMPLAYER_SEEK_NONE;
1736 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1740 case GST_STATE_VOID_PENDING:
1741 case GST_STATE_NULL:
1742 case GST_STATE_READY:
1752 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1754 const gchar *structure_name;
1755 gint count = 0, idx = 0;
1756 MMHandleType attrs = 0;
1759 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1761 attrs = MMPLAYER_GET_ATTRS(player);
1763 LOGE("Failed to get content attribute");
1767 if (gst_message_get_structure(msg) == NULL)
1770 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1771 if (!structure_name)
1774 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1776 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1777 const GValue *var_info = NULL;
1779 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1780 if (var_info != NULL) {
1781 if (player->adaptive_info.var_list)
1782 g_list_free_full(player->adaptive_info.var_list, g_free);
1784 /* share addr or copy the list */
1785 player->adaptive_info.var_list =
1786 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1788 count = g_list_length(player->adaptive_info.var_list);
1790 VariantData *temp = NULL;
1792 /* print out for debug */
1793 LOGD("num of variant_info %d", count);
1794 for (idx = 0; idx < count; idx++) {
1795 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1797 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1803 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1804 gint num_buffers = 0;
1805 gint extra_num_buffers = 0;
1807 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1808 player->video_num_buffers = num_buffers;
1809 LOGD("video_num_buffers : %d", player->video_num_buffers);
1812 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1813 player->video_extra_num_buffers = extra_num_buffers;
1814 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1819 if (!strcmp(structure_name, "Language_list")) {
1820 const GValue *lang_list = NULL;
1821 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1822 if (lang_list != NULL) {
1823 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1825 LOGD("Total audio tracks(from parser) = %d \n", count);
1829 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1830 const GValue *lang_list = NULL;
1831 MMPlayerLangStruct *temp = NULL;
1833 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1834 if (lang_list != NULL) {
1835 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1837 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1838 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1839 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1840 if (mm_attrs_commit_all(attrs))
1841 LOGE("failed to commit.\n");
1842 LOGD("Total subtitle tracks = %d \n", count);
1845 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1847 LOGD("value of lang_key is %s and lang_code is %s",
1848 temp->language_key, temp->language_code);
1851 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1852 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1857 /* custom message */
1858 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1859 MMMessageParamType msg_param = {0,};
1860 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1861 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1864 /* custom message for RTSP attribute :
1865 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1866 sdp which has contents info is received when rtsp connection is opened.
1867 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1868 if (!strcmp(structure_name, "rtspsrc_properties")) {
1870 gchar *audio_codec = NULL;
1871 gchar *video_codec = NULL;
1872 gchar *video_frame_size = NULL;
1874 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1875 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1876 player->streaming_type = __mmplayer_get_stream_service_type(player);
1878 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1879 LOGD("rtsp_audio_codec : %s", audio_codec);
1881 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1883 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1884 LOGD("rtsp_video_codec : %s", video_codec);
1886 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1888 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1889 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1890 if (video_frame_size) {
1892 char *seperator = strchr(video_frame_size, '-');
1895 char video_width[10] = {0,};
1896 int frame_size_len = strlen(video_frame_size);
1897 int separtor_len = strlen(seperator);
1899 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1900 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1903 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1907 if (mm_attrs_commit_all(attrs))
1908 LOGE("failed to commit.\n");
1916 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1918 MMPlayerGstElement *mainbin;
1921 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1923 mainbin = player->pipeline->mainbin;
1925 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1927 /* we only handle messages from pipeline */
1928 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1931 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1932 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1933 player->seek_state = MMPLAYER_SEEK_NONE;
1934 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1935 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1936 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1937 LOGD("sync %s state(%s) with parent state(%s)",
1938 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1939 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1940 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1942 /* In case of streaming, pause is required before finishing seeking by buffering.
1943 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1944 Because the buffering state is controlled according to the state transition for force resume,
1945 the decodebin state should be paused as player state. */
1946 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1949 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1950 (player->streamer) &&
1951 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1952 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1953 GstQuery *query = NULL;
1954 gboolean busy = FALSE;
1957 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1958 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1959 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1960 gst_query_parse_buffering_percent(query, &busy, &percent);
1961 gst_query_unref(query);
1963 LOGD("buffered percent(%s): %d\n",
1964 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1968 __mmplayer_handle_buffering_playback(player);
1971 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1980 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1982 mm_player_t* player = (mm_player_t*)(data);
1984 MMPLAYER_RETURN_IF_FAIL(player);
1985 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1987 switch (GST_MESSAGE_TYPE(msg)) {
1988 case GST_MESSAGE_UNKNOWN:
1989 LOGD("unknown message received\n");
1992 case GST_MESSAGE_EOS:
1993 LOGD("GST_MESSAGE_EOS received");
1994 __mmplayer_gst_handle_eos_message(player, msg);
1997 case GST_MESSAGE_ERROR:
1998 __mmplayer_gst_handle_error_message(player, msg);
2001 case GST_MESSAGE_WARNING:
2004 GError* error = NULL;
2006 gst_message_parse_warning(msg, &error, &debug);
2008 LOGD("warning : %s\n", error->message);
2009 LOGD("debug : %s\n", debug);
2011 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2013 MMPLAYER_FREEIF(debug);
2014 g_error_free(error);
2018 case GST_MESSAGE_TAG:
2020 LOGD("GST_MESSAGE_TAG\n");
2021 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2022 LOGW("failed to extract tags from gstmessage\n");
2026 case GST_MESSAGE_BUFFERING:
2027 __mmplayer_gst_handle_buffering_message(player, msg);
2030 case GST_MESSAGE_STATE_CHANGED:
2031 __mmplayer_gst_handle_state_message(player, msg);
2034 case GST_MESSAGE_CLOCK_LOST:
2036 GstClock *clock = NULL;
2037 gboolean need_new_clock = FALSE;
2039 gst_message_parse_clock_lost(msg, &clock);
2040 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2042 if (!player->videodec_linked)
2043 need_new_clock = TRUE;
2044 else if (!player->ini.use_system_clock)
2045 need_new_clock = TRUE;
2047 if (need_new_clock) {
2048 LOGD("Provide clock is TRUE, do pause->resume\n");
2049 __mmplayer_gst_pause(player, FALSE);
2050 __mmplayer_gst_resume(player, FALSE);
2055 case GST_MESSAGE_NEW_CLOCK:
2057 GstClock *clock = NULL;
2058 gst_message_parse_new_clock(msg, &clock);
2059 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2063 case GST_MESSAGE_ELEMENT:
2064 __mmplayer_gst_handle_element_message(player, msg);
2067 case GST_MESSAGE_DURATION_CHANGED:
2069 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2070 if (!__mmplayer_gst_handle_duration(player, msg))
2071 LOGW("failed to update duration");
2075 case GST_MESSAGE_ASYNC_START:
2076 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2079 case GST_MESSAGE_ASYNC_DONE:
2080 __mmplayer_gst_handle_async_done_message(player, msg);
2083 #if 0 /* delete unnecessary logs */
2084 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2085 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
2086 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
2087 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
2088 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
2089 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2090 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2091 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2092 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2093 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2094 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2095 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
2096 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2097 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2098 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
2105 /* should not call 'gst_message_unref(msg)' */
2109 static GstBusSyncReply
2110 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2112 mm_player_t *player = (mm_player_t *)data;
2113 GstBusSyncReply reply = GST_BUS_DROP;
2115 if (!(player->pipeline && player->pipeline->mainbin)) {
2116 LOGE("player pipeline handle is null");
2117 return GST_BUS_PASS;
2120 if (!__mmplayer_gst_check_useful_message(player, message)) {
2121 gst_message_unref(message);
2122 return GST_BUS_DROP;
2125 switch (GST_MESSAGE_TYPE(message)) {
2126 case GST_MESSAGE_TAG:
2127 __mmplayer_gst_extract_tag_from_msg(player, message);
2131 GstTagList *tags = NULL;
2133 gst_message_parse_tag(message, &tags);
2135 LOGE("TAGS received from element \"%s\".\n",
2136 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2138 gst_tag_list_foreach(tags, print_tag, NULL);
2139 gst_tag_list_free(tags);
2147 case GST_MESSAGE_DURATION_CHANGED:
2148 __mmplayer_gst_handle_duration(player, message);
2150 case GST_MESSAGE_ASYNC_DONE:
2151 /* NOTE:Don't call gst_callback directly
2152 * because previous frame can be showed even though this message is received for seek.
2155 reply = GST_BUS_PASS;
2159 if (reply == GST_BUS_DROP)
2160 gst_message_unref(message);
2166 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2168 GstElement *appsrc = element;
2169 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2170 GstBuffer *buffer = NULL;
2171 GstFlowReturn ret = GST_FLOW_OK;
2174 MMPLAYER_RETURN_IF_FAIL(element);
2175 MMPLAYER_RETURN_IF_FAIL(buf);
2177 buffer = gst_buffer_new();
2179 if (buf->offset < 0 || buf->len < 0) {
2180 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2184 if (buf->offset >= buf->len) {
2185 LOGD("call eos appsrc");
2186 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2190 if (buf->len - buf->offset < size)
2191 len = buf->len - buf->offset;
2193 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2194 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2195 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2197 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2198 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2204 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2206 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2208 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2210 buf->offset = (int)size;
2216 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2218 mm_player_t *player = (mm_player_t*)user_data;
2219 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2220 guint64 current_level_bytes = 0;
2222 MMPLAYER_RETURN_IF_FAIL(player);
2224 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2225 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2226 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2227 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2228 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2229 type = MM_PLAYER_STREAM_TYPE_TEXT;
2231 LOGE("can not enter here");
2235 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2237 LOGI("type: %d, level: %llu", type, current_level_bytes);
2239 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2240 if (player->media_stream_buffer_status_cb[type])
2241 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2242 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2246 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2248 mm_player_t *player = (mm_player_t*)user_data;
2249 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2250 guint64 current_level_bytes = 0;
2252 MMPLAYER_RETURN_IF_FAIL(player);
2254 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2255 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2256 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2257 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2258 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2259 type = MM_PLAYER_STREAM_TYPE_TEXT;
2261 LOGE("can not enter here");
2265 LOGI("type: %d, buffer is full", type);
2267 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2269 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2271 if (player->media_stream_buffer_status_cb[type])
2272 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2274 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2278 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2280 mm_player_t *player = (mm_player_t*)user_data;
2281 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2283 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2285 if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2286 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2287 else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2288 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2289 else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2290 type = MM_PLAYER_STREAM_TYPE_TEXT;
2292 LOGE("can not enter here");
2296 LOGD("type: %d, pos: %llu", type, position);
2297 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2299 if (player->media_stream_seek_data_cb[type])
2300 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2301 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2307 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2309 #define MAX_LEN_NAME 20
2311 gboolean ret = FALSE;
2312 GstPad *sinkpad = NULL;
2313 gchar *prefix = NULL;
2314 gchar dec_name[MAX_LEN_NAME] = {0};
2315 enum MainElementID elem_id = MMPLAYER_M_NUM;
2317 MMPlayerGstElement *mainbin = NULL;
2318 GstElement *decodebin = NULL;
2319 GstCaps *dec_caps = NULL;
2323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2325 player->pipeline->mainbin, FALSE);
2326 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2328 mainbin = player->pipeline->mainbin;
2330 case MM_PLAYER_STREAM_TYPE_AUDIO:
2332 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2334 case MM_PLAYER_STREAM_TYPE_VIDEO:
2336 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2339 LOGE("invalid type %d", type);
2343 if (mainbin[elem_id].gst) {
2344 LOGE("elem(%d) is already created", elem_id);
2348 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2350 /* create decodebin */
2351 decodebin = gst_element_factory_make("decodebin", dec_name);
2353 LOGE("failed to create %s", dec_name);
2357 mainbin[elem_id].id = elem_id;
2358 mainbin[elem_id].gst = decodebin;
2360 /* raw pad handling signal */
2361 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2362 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2364 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2365 before looking for any elements that can handle that stream.*/
2366 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2367 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2369 /* This signal is emitted when a element is added to the bin.*/
2370 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2371 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2373 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2374 LOGE("failed to add new decodebin");
2378 dec_caps = gst_pad_query_caps(srcpad, NULL);
2380 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2381 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2382 gst_caps_unref(dec_caps);
2385 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2387 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2388 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2391 gst_object_unref(GST_OBJECT(sinkpad));
2393 gst_element_sync_state_with_parent(decodebin);
2399 gst_object_unref(GST_OBJECT(sinkpad));
2401 if (mainbin[elem_id].gst) {
2402 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2403 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2404 gst_object_unref(mainbin[elem_id].gst);
2405 mainbin[elem_id].gst = NULL;
2413 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2415 #define MAX_LEN_NAME 20
2416 MMPlayerGstElement *mainbin = NULL;
2417 gchar *prefix = NULL;
2418 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2420 gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2421 GstElement *src = NULL, *queue = NULL;
2422 GstPad *srcpad = NULL;
2425 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2426 player->pipeline->mainbin, FALSE);
2428 mainbin = player->pipeline->mainbin;
2430 LOGD("type(%d) path is creating", type);
2432 case MM_PLAYER_STREAM_TYPE_AUDIO:
2434 if (mainbin[MMPLAYER_M_SRC].gst)
2435 src_id = MMPLAYER_M_2ND_SRC;
2437 src_id = MMPLAYER_M_SRC;
2438 queue_id = MMPLAYER_M_A_BUFFER;
2440 case MM_PLAYER_STREAM_TYPE_VIDEO:
2442 src_id = MMPLAYER_M_SRC;
2443 queue_id = MMPLAYER_M_V_BUFFER;
2445 case MM_PLAYER_STREAM_TYPE_TEXT:
2446 prefix = "subtitle";
2447 src_id = MMPLAYER_M_SUBSRC;
2448 queue_id = MMPLAYER_M_S_BUFFER;
2451 LOGE("invalid type %d", type);
2455 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2456 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2459 src = gst_element_factory_make("appsrc", src_name);
2461 LOGF("failed to create %s", src_name);
2465 mainbin[src_id].id = src_id;
2466 mainbin[src_id].gst = src;
2468 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2469 "caps", caps, NULL);
2471 /* size of many video frames are larger than default blocksize as 4096 */
2472 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2473 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2475 if (player->media_stream_buffer_max_size[type] > 0)
2476 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2478 if (player->media_stream_buffer_min_percent[type] > 0)
2479 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2481 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2482 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2484 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2485 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2486 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2487 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2488 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2489 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2492 queue = gst_element_factory_make("queue2", queue_name);
2494 LOGE("failed to create %s", queue_name);
2497 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2499 mainbin[queue_id].id = queue_id;
2500 mainbin[queue_id].gst = queue;
2502 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2503 LOGE("failed to add src");
2507 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2508 LOGE("failed to add queue");
2512 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2513 LOGE("failed to link src and queue");
2517 /* create decoder */
2518 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2520 LOGE("failed to get srcpad of queue");
2524 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2525 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2527 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2528 LOGE("failed to create decoder");
2529 gst_object_unref(GST_OBJECT(srcpad));
2533 gst_object_unref(GST_OBJECT(srcpad));
2537 if (mainbin[src_id].gst) {
2538 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2539 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2540 gst_object_unref(mainbin[src_id].gst);
2541 mainbin[src_id].gst = NULL;
2544 if (mainbin[queue_id].gst) {
2545 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2546 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2547 gst_object_unref(mainbin[queue_id].gst);
2548 mainbin[queue_id].gst = NULL;
2555 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2557 GstPad *sinkpad = NULL;
2558 GstCaps *caps = NULL;
2559 GstElement *new_element = NULL;
2560 GstStructure *str = NULL;
2561 const gchar *name = NULL;
2562 gboolean caps_ret = TRUE;
2564 mm_player_t *player = (mm_player_t*) data;
2568 MMPLAYER_RETURN_IF_FAIL(element && pad);
2569 MMPLAYER_RETURN_IF_FAIL(player &&
2571 player->pipeline->mainbin);
2573 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2577 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2578 * num_dynamic_pad will decreased after creating a sinkbin.
2580 player->num_dynamic_pad++;
2581 LOGD("stream count inc : %d", player->num_dynamic_pad);
2583 /* clear previous result*/
2584 player->have_dynamic_pad = FALSE;
2586 if (strstr(name, "video")) {
2588 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2590 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2591 if (player->v_stream_caps) {
2592 gst_caps_unref(player->v_stream_caps);
2593 player->v_stream_caps = NULL;
2596 new_element = gst_element_factory_make("fakesink", NULL);
2597 player->num_dynamic_pad--;
2602 /* clear previous result*/
2603 player->have_dynamic_pad = FALSE;
2605 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2606 LOGE("failed to autoplug for caps");
2610 /* check if there's dynamic pad*/
2611 if (player->have_dynamic_pad) {
2612 LOGE("using pad caps assums there's no dynamic pad !\n");
2616 gst_caps_unref(caps);
2621 /* excute new_element if created*/
2623 LOGD("adding new element to pipeline\n");
2625 /* set state to READY before add to bin */
2626 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2628 /* add new element to the pipeline */
2629 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2630 LOGE("failed to add autoplug element to bin\n");
2634 /* get pad from element */
2635 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2637 LOGE("failed to get sinkpad from autoplug element\n");
2642 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2643 LOGE("failed to link autoplug element\n");
2647 gst_object_unref(sinkpad);
2650 /* run. setting PLAYING here since streamming source is live source */
2651 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2655 gst_caps_unref(caps);
2661 STATE_CHANGE_FAILED:
2663 /* FIXIT : take care if new_element has already added to pipeline */
2665 gst_object_unref(GST_OBJECT(new_element));
2668 gst_object_unref(GST_OBJECT(sinkpad));
2671 gst_caps_unref(caps);
2673 /* FIXIT : how to inform this error to MSL ????? */
2674 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2675 * then post an error to application
2680 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2682 mm_player_t* player = (mm_player_t*) data;
2686 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2687 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2688 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2689 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2691 * [1] audio and video will be dumped with filesink.
2692 * [2] autoplugging is done by just using pad caps.
2693 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2694 * and the video will be dumped via filesink.
2696 if (player->num_dynamic_pad == 0) {
2697 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2699 if (!__mmplayer_gst_remove_fakesink(player,
2700 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2701 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2702 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2703 * source element are not same. To overcome this situation, this function will called
2704 * several places and several times. Therefore, this is not an error case.
2709 /* create dot before error-return. for debugging */
2710 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2712 player->no_more_pad = TRUE;
2718 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2720 GstElement* element = NULL;
2721 gchar *user_agent = NULL;
2722 MMHandleType attrs = 0;
2725 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2727 /* get profile attribute */
2728 attrs = MMPLAYER_GET_ATTRS(player);
2730 LOGE("failed to get content attribute");
2734 element = gst_element_factory_make("rtspsrc", "rtsp source");
2736 LOGE("failed to create rtspsrc element");
2741 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2743 SECURE_LOGD("user_agent : %s", user_agent);
2745 /* setting property to streaming source */
2746 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2748 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2750 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2751 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2752 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2753 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2760 __mmplayer_gst_make_http_src(mm_player_t* player)
2762 GstElement* element = NULL;
2763 MMHandleType attrs = 0;
2764 gchar *user_agent, *cookies, **cookie_list;
2765 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2766 user_agent = cookies = NULL;
2770 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2772 /* get profile attribute */
2773 attrs = MMPLAYER_GET_ATTRS(player);
2775 LOGE("failed to get content attribute");
2779 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2781 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2783 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2788 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2789 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2791 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2792 http_timeout = player->ini.http_timeout;
2795 SECURE_LOGD("location : %s", player->profile.uri);
2796 SECURE_LOGD("cookies : %s", cookies);
2797 SECURE_LOGD("user_agent : %s", user_agent);
2798 LOGD("timeout : %d", http_timeout);
2800 /* setting property to streaming source */
2801 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2802 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2804 /* parsing cookies */
2805 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2806 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2807 g_strfreev(cookie_list);
2811 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2813 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2814 LOGW("[DASH] this is still experimental feature");
2821 __mmplayer_gst_make_file_src(mm_player_t* player)
2823 GstElement* element = NULL;
2826 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2828 LOGD("using filesrc for 'file://' handler");
2829 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2830 LOGE("failed to get storage info");
2834 element = gst_element_factory_make("filesrc", "source");
2836 LOGE("failed to create filesrc");
2840 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2846 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2848 mm_player_t *player = (mm_player_t *) data;
2850 g_return_val_if_fail(player, FALSE);
2851 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2853 gst_message_ref(msg);
2855 g_mutex_lock(&player->bus_msg_q_lock);
2856 g_queue_push_tail(player->bus_msg_q, msg);
2857 g_mutex_unlock(&player->bus_msg_q_lock);
2859 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2860 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2861 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2865 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2867 mm_player_t *player = (mm_player_t*)(data);
2868 GstMessage *msg = NULL;
2872 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2874 player->pipeline->mainbin &&
2875 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2878 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2880 LOGE("cannot get BUS from the pipeline");
2884 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2886 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2887 while (!player->bus_msg_thread_exit) {
2888 g_mutex_lock(&player->bus_msg_q_lock);
2889 msg = g_queue_pop_head(player->bus_msg_q);
2890 g_mutex_unlock(&player->bus_msg_q_lock);
2892 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2895 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2896 /* handle the gst msg */
2897 __mmplayer_gst_bus_msg_callback(msg, player);
2898 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2899 gst_message_unref(msg);
2902 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2903 gst_object_unref(GST_OBJECT(bus));
2910 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2912 gint64 dur_nsec = 0;
2915 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2918 return MM_ERROR_NONE;
2920 /* NOTE : duration cannot be zero except live streaming.
2921 * Since some element could have some timing problemn with quering duration, try again.
2923 if (player->duration == 0) {
2924 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2925 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2926 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2927 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2928 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2929 player->pending_seek.is_pending = TRUE;
2930 player->pending_seek.pos = position;
2931 player->seek_state = MMPLAYER_SEEK_NONE;
2932 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2933 return MM_ERROR_PLAYER_NO_OP;
2935 player->seek_state = MMPLAYER_SEEK_NONE;
2936 return MM_ERROR_PLAYER_SEEK;
2939 player->duration = dur_nsec;
2942 if (player->duration > 0 && player->duration < position) {
2943 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2944 return MM_ERROR_INVALID_ARGUMENT;
2948 return MM_ERROR_NONE;
2952 __mmplayer_gst_check_seekable(mm_player_t* player)
2954 GstQuery *query = NULL;
2955 gboolean seekable = FALSE;
2957 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2961 query = gst_query_new_seeking(GST_FORMAT_TIME);
2962 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2963 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2964 gst_query_unref(query);
2967 LOGW("non-seekable content");
2968 player->seek_state = MMPLAYER_SEEK_NONE;
2972 LOGW("failed to get seeking query");
2973 gst_query_unref(query); /* keep seeking operation */
2984 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2986 GstState element_state = GST_STATE_VOID_PENDING;
2987 GstState element_pending_state = GST_STATE_VOID_PENDING;
2988 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2993 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2995 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2998 ret = gst_element_set_state(element, state);
3000 if (ret == GST_STATE_CHANGE_FAILURE) {
3001 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3003 /* dump state of all element */
3004 __mmplayer_dump_pipeline_state(player);
3006 return MM_ERROR_PLAYER_INTERNAL;
3009 /* return here so state transition to be done in async mode */
3011 LOGD("async state transition. not waiting for state complete.\n");
3012 return MM_ERROR_NONE;
3015 /* wait for state transition */
3016 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3018 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3019 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3020 GST_ELEMENT_NAME(element),
3021 gst_element_state_get_name(state), timeout);
3023 LOGE(" [%s] state : %s pending : %s \n",
3024 GST_ELEMENT_NAME(element),
3025 gst_element_state_get_name(element_state),
3026 gst_element_state_get_name(element_pending_state));
3028 /* dump state of all element */
3029 __mmplayer_dump_pipeline_state(player);
3031 return MM_ERROR_PLAYER_INTERNAL;
3034 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3038 return MM_ERROR_NONE;
3041 int __mmplayer_gst_start(mm_player_t* player)
3043 int ret = MM_ERROR_NONE;
3044 gboolean async = FALSE;
3048 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3050 /* NOTE : if SetPosition was called before Start. do it now */
3051 /* streaming doesn't support it. so it should be always sync */
3052 /* !!create one more api to check if there is pending seek rather than checking variables */
3053 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3054 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3055 ret = __mmplayer_gst_pause(player, FALSE);
3056 if (ret != MM_ERROR_NONE) {
3057 LOGE("failed to set state to PAUSED for pending seek");
3061 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3062 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3063 LOGW("failed to seek pending postion. starting from the begin of content");
3066 LOGD("current state before doing transition");
3067 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3068 MMPLAYER_PRINT_STATE(player);
3070 /* set pipeline state to PLAYING */
3071 ret = __mmplayer_gst_set_state(player,
3072 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3074 if (ret == MM_ERROR_NONE) {
3075 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3077 LOGE("failed to set state to PLAYING");
3081 /* generating debug info before returning error */
3082 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3089 int __mmplayer_gst_stop(mm_player_t* player)
3091 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3092 MMHandleType attrs = 0;
3093 gboolean rewind = FALSE;
3095 int ret = MM_ERROR_NONE;
3099 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3100 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3102 LOGD("current state before doing transition");
3103 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3104 MMPLAYER_PRINT_STATE(player);
3106 attrs = MMPLAYER_GET_ATTRS(player);
3108 LOGE("cannot get content attribute\n");
3109 return MM_ERROR_PLAYER_INTERNAL;
3112 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3113 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3115 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3116 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3119 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3120 /* disable the async state transition because there could be no data in the pipeline */
3121 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3125 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3127 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3128 /* enable the async state transition as default operation */
3129 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3132 /* return if set_state has failed */
3133 if (ret != MM_ERROR_NONE) {
3134 LOGE("failed to set state.\n");
3140 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3141 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3142 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3143 LOGW("failed to rewind\n");
3144 ret = MM_ERROR_PLAYER_SEEK;
3149 player->sent_bos = FALSE;
3151 if (player->es_player_push_mode) //for cloudgame
3154 /* wait for seek to complete */
3155 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3156 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3157 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3159 LOGE("fail to stop player.\n");
3160 ret = MM_ERROR_PLAYER_INTERNAL;
3161 __mmplayer_dump_pipeline_state(player);
3164 /* generate dot file if enabled */
3165 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3172 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3174 int ret = MM_ERROR_NONE;
3178 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3179 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3181 LOGD("current state before doing transition");
3182 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3183 MMPLAYER_PRINT_STATE(player);
3185 /* set pipeline status to PAUSED */
3186 ret = __mmplayer_gst_set_state(player,
3187 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3189 if (FALSE == async) {
3190 if (ret != MM_ERROR_NONE) {
3191 GstMessage *msg = NULL;
3192 GTimer *timer = NULL;
3193 gdouble MAX_TIMEOUT_SEC = 3;
3195 LOGE("failed to set state to PAUSED");
3197 if (!player->bus_watcher) {
3198 LOGE("there is no bus msg thread. pipeline is shutting down.");
3202 if (player->msg_posted) {
3203 LOGE("error msg is already posted.");
3207 timer = g_timer_new();
3208 g_timer_start(timer);
3210 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3213 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3215 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3216 GError *error = NULL;
3218 /* parse error code */
3219 gst_message_parse_error(msg, &error, NULL);
3221 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3222 /* Note : the streaming error from the streaming source is handled
3223 * using __mmplayer_handle_streaming_error.
3225 __mmplayer_handle_streaming_error(player, msg);
3228 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3230 if (error->domain == GST_STREAM_ERROR)
3231 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3232 else if (error->domain == GST_RESOURCE_ERROR)
3233 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3234 else if (error->domain == GST_LIBRARY_ERROR)
3235 ret = __mmplayer_gst_handle_library_error(player, error->code);
3236 else if (error->domain == GST_CORE_ERROR)
3237 ret = __mmplayer_gst_handle_core_error(player, error->code);
3239 g_error_free(error);
3241 player->msg_posted = TRUE;
3243 gst_message_unref(msg);
3245 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3247 gst_object_unref(bus);
3248 g_timer_stop(timer);
3249 g_timer_destroy(timer);
3253 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3254 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3256 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3259 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3263 /* generate dot file before returning error */
3264 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3271 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3273 int ret = MM_ERROR_NONE;
3278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3279 MM_ERROR_PLAYER_NOT_INITIALIZED);
3281 LOGD("current state before doing transition");
3282 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3283 MMPLAYER_PRINT_STATE(player);
3286 LOGD("do async state transition to PLAYING");
3288 /* set pipeline state to PLAYING */
3289 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3291 ret = __mmplayer_gst_set_state(player,
3292 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3293 if (ret != MM_ERROR_NONE) {
3294 LOGE("failed to set state to PLAYING");
3298 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3302 /* generate dot file */
3303 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3310 /* sending event to one of sinkelements */
3312 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3314 GstEvent * event2 = NULL;
3315 GList *sinks = NULL;
3316 gboolean res = FALSE;
3319 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3320 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3322 /* While adding subtitles in live feeds seek is getting called.
3323 Adding defensive check in framework layer.*/
3324 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3325 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3326 LOGE("Should not send seek event during live playback");
3331 if (player->play_subtitle)
3332 event2 = gst_event_copy((const GstEvent *)event);
3334 sinks = player->sink_elements;
3336 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3338 if (GST_IS_ELEMENT(sink)) {
3339 /* keep ref to the event */
3340 gst_event_ref(event);
3342 if ((res = gst_element_send_event(sink, event))) {
3343 LOGD("sending event[%s] to sink element [%s] success!\n",
3344 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3346 /* rtsp case, asyn_done is not called after seek during pause state */
3347 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3348 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3349 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3350 LOGD("RTSP seek completed, after pause state..\n");
3351 player->seek_state = MMPLAYER_SEEK_NONE;
3352 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3358 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3359 sinks = g_list_next(sinks);
3366 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3367 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3370 sinks = g_list_next(sinks);
3373 /* Note : Textbin is not linked to the video or audio bin.
3374 * It needs to send the event to the text sink seperatelly.
3376 if (player->play_subtitle && player->pipeline) {
3377 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3379 if (GST_IS_ELEMENT(text_sink)) {
3380 /* keep ref to the event */
3381 gst_event_ref(event2);
3383 if ((res = gst_element_send_event(text_sink, event2)))
3384 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3385 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3387 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3388 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3390 gst_event_unref(event2);
3394 gst_event_unref(event);
3402 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3403 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3404 gint64 cur, GstSeekType stop_type, gint64 stop)
3406 GstEvent* event = NULL;
3407 gboolean result = FALSE;
3411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3413 if (player->pipeline && player->pipeline->textbin)
3414 __mmplayer_drop_subtitle(player, FALSE);
3416 event = gst_event_new_seek(rate, format, flags, cur_type,
3417 cur, stop_type, stop);
3419 result = __mmplayer_gst_send_event_to_sink(player, event);
3427 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3429 int ret = MM_ERROR_NONE;
3430 gint64 pos_nsec = 0;
3431 gboolean accurated = FALSE;
3432 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3435 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3436 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3438 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3439 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3442 ret = __mmplayer_gst_check_duration(player, position);
3443 if (ret != MM_ERROR_NONE) {
3444 LOGE("failed to check duration 0x%X", ret);
3445 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3448 if (!__mmplayer_gst_check_seekable(player))
3449 return MM_ERROR_PLAYER_NO_OP;
3451 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3452 position, player->playback_rate, player->duration);
3454 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3455 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3456 This causes problem is position calculation during normal pause resume scenarios also.
3457 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3458 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3459 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3460 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3461 LOGW("getting current position failed in seek");
3463 player->last_position = pos_nsec;
3464 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3467 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3468 LOGD("not completed seek");
3469 return MM_ERROR_PLAYER_DOING_SEEK;
3472 if (!internal_called)
3473 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3475 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3476 that's why set position through property. */
3477 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3478 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3479 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3480 (!player->videodec_linked) && (!player->audiodec_linked)) {
3482 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3483 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3485 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3486 player->seek_state = MMPLAYER_SEEK_NONE;
3487 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3489 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3491 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3493 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3495 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3496 GST_FORMAT_TIME, seek_flags,
3497 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3498 LOGE("failed to set position");
3503 /* NOTE : store last seeking point to overcome some bad operation
3504 * (returning zero when getting current position) of some elements
3506 player->last_position = position;
3508 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3509 if (player->playback_rate > 1.0)
3510 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3512 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3513 LOGD("buffering should be reset after seeking");
3514 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3515 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3519 return MM_ERROR_NONE;
3522 player->pending_seek.is_pending = TRUE;
3523 player->pending_seek.pos = position;
3525 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3526 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3527 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3528 player->pending_seek.pos);
3530 return MM_ERROR_NONE;
3533 player->seek_state = MMPLAYER_SEEK_NONE;
3534 return MM_ERROR_PLAYER_SEEK;
3538 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3540 #define TRICKPLAY_OFFSET GST_MSECOND
3542 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3543 gint64 pos_nsec = 0;
3544 gboolean ret = TRUE;
3546 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3547 MM_ERROR_PLAYER_NOT_INITIALIZED);
3549 current_state = MMPLAYER_CURRENT_STATE(player);
3551 /* NOTE : query position except paused state to overcome some bad operation
3552 * please refer to below comments in details
3554 if (current_state != MM_PLAYER_STATE_PAUSED)
3555 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3557 /* NOTE : get last point to overcome some bad operation of some elements
3558 *(returning zero when getting current position in paused state
3559 * and when failed to get postion during seeking
3561 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3562 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3564 if (player->playback_rate < 0.0)
3565 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3567 pos_nsec = player->last_position;
3570 pos_nsec = player->last_position;
3572 player->last_position = pos_nsec;
3574 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3577 if (player->duration > 0 && pos_nsec > player->duration)
3578 pos_nsec = player->duration;
3580 player->last_position = pos_nsec;
3583 *position = pos_nsec;
3585 return MM_ERROR_NONE;
3588 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3590 #define STREAMING_IS_FINISHED 0
3591 #define BUFFERING_MAX_PER 100
3592 #define DEFAULT_PER_VALUE -1
3593 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3595 MMPlayerGstElement *mainbin = NULL;
3596 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3597 gint64 buffered_total = 0;
3598 gint64 position = 0;
3599 gint buffered_sec = -1;
3600 GstBufferingMode mode = GST_BUFFERING_STREAM;
3601 gint64 content_size_time = player->duration;
3602 guint64 content_size_bytes = player->http_content_size;
3604 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3606 player->pipeline->mainbin,
3607 MM_ERROR_PLAYER_NOT_INITIALIZED);
3609 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3614 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3615 /* and rtsp is not ready yet. */
3616 LOGW("it's only used for http streaming case");
3617 return MM_ERROR_PLAYER_NO_OP;
3620 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3621 LOGW("Time format is not supported yet");
3622 return MM_ERROR_INVALID_ARGUMENT;
3625 if (content_size_time <= 0 || content_size_bytes <= 0) {
3626 LOGW("there is no content size");
3627 return MM_ERROR_NONE;
3630 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3631 LOGW("fail to get current position");
3632 return MM_ERROR_NONE;
3635 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3636 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3638 mainbin = player->pipeline->mainbin;
3639 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3641 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3642 GstQuery *query = NULL;
3643 gint byte_in_rate = 0, byte_out_rate = 0;
3644 gint64 estimated_total = 0;
3646 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3647 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3648 LOGW("fail to get buffering query from queue2");
3650 gst_query_unref(query);
3651 return MM_ERROR_NONE;
3654 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3655 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3657 if (mode == GST_BUFFERING_STREAM) {
3658 /* using only queue in case of push mode(ts / mp3) */
3659 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3660 GST_FORMAT_BYTES, &buffered_total)) {
3661 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3662 stop_per = 100 * buffered_total / content_size_bytes;
3665 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3667 guint num_of_ranges = 0;
3668 gint64 start_byte = 0, stop_byte = 0;
3670 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3671 if (estimated_total != STREAMING_IS_FINISHED) {
3672 /* buffered size info from queue2 */
3673 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3674 for (idx = 0; idx < num_of_ranges; idx++) {
3675 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3676 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3678 buffered_total += (stop_byte - start_byte);
3681 stop_per = BUFFERING_MAX_PER;
3683 gst_query_unref(query);
3686 if (stop_per == DEFAULT_PER_VALUE) {
3687 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3689 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3691 /* buffered size info from multiqueue */
3692 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3693 guint curr_size_bytes = 0;
3694 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3695 "curr-size-bytes", &curr_size_bytes, NULL);
3696 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3697 buffered_total += curr_size_bytes;
3700 if (avg_byterate > 0)
3701 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3702 else if (player->total_maximum_bitrate > 0)
3703 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3704 else if (player->total_bitrate > 0)
3705 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3707 if (buffered_sec >= 0)
3708 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3712 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3713 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3715 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3716 buffered_total, buffered_sec, *start_pos, *stop_pos);
3718 return MM_ERROR_NONE;
3721 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3723 GstElement* element = NULL;
3726 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3727 player->pipeline->mainbin, NULL);
3729 /* setup source for gapless play */
3730 switch (player->profile.uri_type) {
3732 case MM_PLAYER_URI_TYPE_FILE:
3733 element = __mmplayer_gst_make_file_src(player);
3735 case MM_PLAYER_URI_TYPE_URL_HTTP:
3736 element = __mmplayer_gst_make_http_src(player);
3739 LOGE("not support uri type %d", player->profile.uri_type);
3744 LOGE("failed to create source element");
3752 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3754 MMHandleType attrs = 0;
3757 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3758 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3760 /* get profile attribute */
3761 attrs = MMPLAYER_GET_ATTRS(player);
3763 LOGE("failed to get content attribute");
3764 return MM_ERROR_PLAYER_INTERNAL;
3767 SECURE_LOGD("uri : %s", player->profile.uri);
3769 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3770 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3771 LOGE("failed to commit");
3773 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3774 return MM_ERROR_PLAYER_INTERNAL;
3776 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3777 return MM_ERROR_PLAYER_INTERNAL;
3779 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3780 return MM_ERROR_PLAYER_INTERNAL;
3783 return MM_ERROR_NONE;
3786 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3788 MMPlayerGstElement *mainbin = NULL;
3789 GstElement *pd_src = NULL;
3790 GstElement *pd_queue = NULL;
3791 GstElement *pd_decodebin = NULL;
3792 GList* element_bucket = NULL;
3793 MMHandleType attrs = 0;
3795 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3798 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3799 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3801 /* get profile attribute */
3802 attrs = MMPLAYER_GET_ATTRS(player);
3804 LOGE("failed to get content attribute");
3805 return MM_ERROR_PLAYER_INTERNAL;
3808 LOGD("http playback with progressive download : %d", player->pd_mode);
3810 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3811 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3812 MMPLAYER_FREEIF(player->pd_file_save_path);
3814 SECURE_LOGD("PD Location : %s", path);
3816 LOGE("filed to find pd location");
3817 return MM_ERROR_PLAYER_INTERNAL;
3820 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3821 LOGE("failed to get storage info");
3822 return MM_ERROR_PLAYER_INTERNAL;
3824 player->pd_file_save_path = g_strdup(path);
3827 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3829 LOGE("failed to create PD push source");
3830 return MM_ERROR_PLAYER_INTERNAL;
3833 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3834 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3836 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3838 mainbin = player->pipeline->mainbin;
3840 /* take source element */
3841 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3842 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3843 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3846 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3847 pd_queue = gst_element_factory_make("queue2", "queue2");
3849 LOGE("failed to create pd buffer element");
3854 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3855 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3856 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3858 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3860 player->streamer->is_pd_mode = TRUE;
3862 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3863 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3864 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3866 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3867 if (!pd_decodebin) {
3868 LOGE("failed to create decodebin");
3872 /* default size of mq in decodebin is 2M
3873 * but it can cause blocking issue during seeking depends on content. */
3874 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3876 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3877 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3879 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3881 /* add elements to pipeline */
3882 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3883 LOGE("failed to add elements to pipeline");
3887 /* linking elements in the bucket by added order. */
3888 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3889 LOGE("failed to link some elements");
3893 g_list_free(element_bucket);
3896 return MM_ERROR_NONE;
3899 MMPLAYER_FREEIF(player->pd_file_save_path);
3900 g_list_free(element_bucket);
3902 if (mainbin[MMPLAYER_M_SRC].gst)
3903 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3905 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3906 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3908 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3909 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3911 mainbin[MMPLAYER_M_SRC].gst = NULL;
3912 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3913 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3915 return MM_ERROR_PLAYER_INTERNAL;
3918 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3920 MMPlayerGstElement *mainbin = NULL;
3921 GstElement* src_elem = NULL;
3922 GstElement *autoplug_elem = NULL;
3923 GList* element_bucket = NULL;
3924 MMHandleType attrs = 0;
3925 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3928 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3929 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3931 /* get profile attribute */
3932 attrs = MMPLAYER_GET_ATTRS(player);
3934 LOGE("failed to get content attribute");
3935 return MM_ERROR_PLAYER_INTERNAL;
3938 LOGD("uri type %d", player->profile.uri_type);
3940 /* create source element */
3941 switch (player->profile.uri_type) {
3942 case MM_PLAYER_URI_TYPE_URL_RTSP:
3943 src_elem = __mmplayer_gst_make_rtsp_src(player);
3945 case MM_PLAYER_URI_TYPE_URL_HTTP:
3946 src_elem = __mmplayer_gst_make_http_src(player);
3948 case MM_PLAYER_URI_TYPE_FILE:
3949 src_elem = __mmplayer_gst_make_file_src(player);
3951 case MM_PLAYER_URI_TYPE_SS:
3953 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3954 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3956 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3960 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3961 LOGD("get timeout from ini");
3962 http_timeout = player->ini.http_timeout;
3965 /* setting property to streaming source */
3966 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3969 case MM_PLAYER_URI_TYPE_MEM:
3971 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3973 src_elem = gst_element_factory_make("appsrc", "mem-source");
3975 LOGE("failed to create appsrc element");
3979 g_object_set(src_elem, "stream-type", stream_type,
3980 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3982 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3983 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3984 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3985 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3989 LOGE("not support uri type");
3994 LOGE("failed to create source element");
3995 return MM_ERROR_PLAYER_INTERNAL;
3998 mainbin = player->pipeline->mainbin;
4000 /* take source element */
4001 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4003 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4004 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4005 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4007 /* create next element for auto-plugging */
4008 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4009 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4010 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4011 if (!autoplug_elem) {
4012 LOGE("failed to create typefind element");
4016 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4017 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4018 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4019 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4020 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4021 if (!autoplug_elem) {
4022 LOGE("failed to create decodebin");
4026 /* default size of mq in decodebin is 2M
4027 * but it can cause blocking issue during seeking depends on content. */
4028 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4031 if (autoplug_elem) {
4032 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4033 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4034 mainbin[autoplug_elem_id].gst = autoplug_elem;
4036 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4039 /* add elements to pipeline */
4040 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4041 LOGE("failed to add elements to pipeline");
4045 /* linking elements in the bucket by added order. */
4046 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4047 LOGE("failed to link some elements");
4051 /* FIXME: need to check whether this is required or not. */
4052 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4053 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4054 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4055 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4057 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4058 LOGE("failed to create fakesink");
4061 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4063 /* take ownership of fakesink. we are reusing it */
4064 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4066 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4067 LOGE("failed to add fakesink to bin");
4068 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4073 g_list_free(element_bucket);
4076 return MM_ERROR_NONE;
4079 g_list_free(element_bucket);
4081 if (mainbin[MMPLAYER_M_SRC].gst)
4082 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4084 if (mainbin[autoplug_elem_id].gst)
4085 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4087 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4088 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4090 mainbin[MMPLAYER_M_SRC].gst = NULL;
4091 mainbin[autoplug_elem_id].gst = NULL;
4092 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4094 return MM_ERROR_PLAYER_INTERNAL;
4097 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4100 MMPlayerGstElement *mainbin = NULL;
4103 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4104 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4106 mainbin = player->pipeline->mainbin;
4108 /* connect bus callback */
4109 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4111 LOGE("cannot get bus from pipeline");
4112 return MM_ERROR_PLAYER_INTERNAL;
4115 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4116 player->context.thread_default = g_main_context_get_thread_default();
4117 if (player->context.thread_default == NULL) {
4118 player->context.thread_default = g_main_context_default();
4119 LOGD("thread-default context is the global default context");
4121 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4123 /* set sync handler to get tag synchronously */
4124 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4125 gst_object_unref(GST_OBJECT(bus));
4127 /* create gst bus_msb_cb thread */
4128 g_mutex_init(&player->bus_msg_thread_mutex);
4129 g_cond_init(&player->bus_msg_thread_cond);
4130 player->bus_msg_thread_exit = FALSE;
4131 player->bus_msg_thread =
4132 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4133 if (!player->bus_msg_thread) {
4134 LOGE("failed to create gst BUS msg thread");
4135 g_mutex_clear(&player->bus_msg_thread_mutex);
4136 g_cond_clear(&player->bus_msg_thread_cond);
4137 return MM_ERROR_PLAYER_INTERNAL;
4141 return MM_ERROR_NONE;