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;
2563 mm_player_t *player = (mm_player_t*) data;
2567 MMPLAYER_RETURN_IF_FAIL(element && pad);
2568 MMPLAYER_RETURN_IF_FAIL(player &&
2570 player->pipeline->mainbin);
2572 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2573 * num_dynamic_pad will decreased after creating a sinkbin.
2575 player->num_dynamic_pad++;
2576 LOGD("stream count inc : %d", player->num_dynamic_pad);
2578 caps = gst_pad_query_caps(pad, NULL);
2579 MMPLAYER_CHECK_NULL(caps);
2581 str = gst_caps_get_structure (caps, 0);
2582 name = gst_structure_get_string(str, "media");
2584 LOGE("cannot get mimetype from structure.\n");
2588 if (strstr(name, "video")) {
2590 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2592 if ((stype == MM_DISPLAY_SURFACE_NULL) && (player->set_mode.media_packet_video_stream == FALSE)) {
2593 if (player->v_stream_caps) {
2594 gst_caps_unref(player->v_stream_caps);
2595 player->v_stream_caps = NULL;
2598 new_element = gst_element_factory_make("fakesink", NULL);
2599 player->num_dynamic_pad--;
2604 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2605 LOGE("failed to autoplug for caps");
2609 gst_caps_unref(caps);
2614 /* excute new_element if created*/
2616 LOGD("adding new element to pipeline\n");
2618 /* set state to READY before add to bin */
2619 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2621 /* add new element to the pipeline */
2622 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2623 LOGE("failed to add autoplug element to bin\n");
2627 /* get pad from element */
2628 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2630 LOGE("failed to get sinkpad from autoplug element\n");
2635 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2636 LOGE("failed to link autoplug element\n");
2640 gst_object_unref(sinkpad);
2643 /* run. setting PLAYING here since streamming source is live source */
2644 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2648 gst_caps_unref(caps);
2654 STATE_CHANGE_FAILED:
2656 /* FIXIT : take care if new_element has already added to pipeline */
2658 gst_object_unref(GST_OBJECT(new_element));
2661 gst_object_unref(GST_OBJECT(sinkpad));
2664 gst_caps_unref(caps);
2666 /* FIXIT : how to inform this error to MSL ????? */
2667 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2668 * then post an error to application
2673 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2675 mm_player_t* player = (mm_player_t*) data;
2679 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2680 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2681 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2682 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2684 * [1] audio and video will be dumped with filesink.
2685 * [2] autoplugging is done by just using pad caps.
2686 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2687 * and the video will be dumped via filesink.
2689 if (player->num_dynamic_pad == 0) {
2690 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2692 if (!__mmplayer_gst_remove_fakesink(player,
2693 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2694 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2695 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2696 * source element are not same. To overcome this situation, this function will called
2697 * several places and several times. Therefore, this is not an error case.
2702 /* create dot before error-return. for debugging */
2703 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2705 player->no_more_pad = TRUE;
2711 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2713 GstElement* element = NULL;
2714 gchar *user_agent = NULL;
2715 MMHandleType attrs = 0;
2718 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2720 /* get profile attribute */
2721 attrs = MMPLAYER_GET_ATTRS(player);
2723 LOGE("failed to get content attribute");
2727 element = gst_element_factory_make("rtspsrc", "rtsp source");
2729 LOGE("failed to create rtspsrc element");
2734 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2736 SECURE_LOGD("user_agent : %s", user_agent);
2738 /* setting property to streaming source */
2739 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2741 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2743 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2744 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2745 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2746 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2753 __mmplayer_gst_make_http_src(mm_player_t* player)
2755 GstElement* element = NULL;
2756 MMHandleType attrs = 0;
2757 gchar *user_agent, *cookies, **cookie_list;
2758 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2759 user_agent = cookies = NULL;
2763 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2765 /* get profile attribute */
2766 attrs = MMPLAYER_GET_ATTRS(player);
2768 LOGE("failed to get content attribute");
2772 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2774 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2776 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2781 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2782 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2784 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2785 http_timeout = player->ini.http_timeout;
2788 SECURE_LOGD("location : %s", player->profile.uri);
2789 SECURE_LOGD("cookies : %s", cookies);
2790 SECURE_LOGD("user_agent : %s", user_agent);
2791 LOGD("timeout : %d", http_timeout);
2793 /* setting property to streaming source */
2794 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2795 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2797 /* parsing cookies */
2798 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2799 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2800 g_strfreev(cookie_list);
2804 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2806 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2807 LOGW("[DASH] this is still experimental feature");
2814 __mmplayer_gst_make_file_src(mm_player_t* player)
2816 GstElement* element = NULL;
2819 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2821 LOGD("using filesrc for 'file://' handler");
2822 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2823 LOGE("failed to get storage info");
2827 element = gst_element_factory_make("filesrc", "source");
2829 LOGE("failed to create filesrc");
2833 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2839 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2841 mm_player_t *player = (mm_player_t *) data;
2843 g_return_val_if_fail(player, FALSE);
2844 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2846 gst_message_ref(msg);
2848 g_mutex_lock(&player->bus_msg_q_lock);
2849 g_queue_push_tail(player->bus_msg_q, msg);
2850 g_mutex_unlock(&player->bus_msg_q_lock);
2852 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2853 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2854 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2858 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2860 mm_player_t *player = (mm_player_t*)(data);
2861 GstMessage *msg = NULL;
2865 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2867 player->pipeline->mainbin &&
2868 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2871 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2873 LOGE("cannot get BUS from the pipeline");
2877 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2879 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2880 while (!player->bus_msg_thread_exit) {
2881 g_mutex_lock(&player->bus_msg_q_lock);
2882 msg = g_queue_pop_head(player->bus_msg_q);
2883 g_mutex_unlock(&player->bus_msg_q_lock);
2885 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2888 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2889 /* handle the gst msg */
2890 __mmplayer_gst_bus_msg_callback(msg, player);
2891 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2892 gst_message_unref(msg);
2895 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2896 gst_object_unref(GST_OBJECT(bus));
2903 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2905 gint64 dur_nsec = 0;
2908 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2910 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2911 return MM_ERROR_NONE;
2913 /* NOTE : duration cannot be zero except live streaming.
2914 * Since some element could have some timing problemn with quering duration, try again.
2916 if (player->duration == 0) {
2917 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2918 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2919 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2920 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2921 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2922 player->pending_seek.is_pending = TRUE;
2923 player->pending_seek.pos = position;
2924 player->seek_state = MMPLAYER_SEEK_NONE;
2925 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2926 return MM_ERROR_PLAYER_NO_OP;
2928 player->seek_state = MMPLAYER_SEEK_NONE;
2929 return MM_ERROR_PLAYER_SEEK;
2932 player->duration = dur_nsec;
2935 if (player->duration > 0 && player->duration < position) {
2936 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2937 return MM_ERROR_INVALID_ARGUMENT;
2941 return MM_ERROR_NONE;
2945 __mmplayer_gst_check_seekable(mm_player_t* player)
2947 GstQuery *query = NULL;
2948 gboolean seekable = FALSE;
2950 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2954 query = gst_query_new_seeking(GST_FORMAT_TIME);
2955 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2956 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2957 gst_query_unref(query);
2960 LOGW("non-seekable content");
2961 player->seek_state = MMPLAYER_SEEK_NONE;
2965 LOGW("failed to get seeking query");
2966 gst_query_unref(query); /* keep seeking operation */
2977 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout)
2979 GstState element_state = GST_STATE_VOID_PENDING;
2980 GstState element_pending_state = GST_STATE_VOID_PENDING;
2981 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2985 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2986 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2988 LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2991 ret = gst_element_set_state(element, state);
2993 if (ret == GST_STATE_CHANGE_FAILURE) {
2994 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2996 /* dump state of all element */
2997 __mmplayer_dump_pipeline_state(player);
2999 return MM_ERROR_PLAYER_INTERNAL;
3002 /* return here so state transition to be done in async mode */
3004 LOGD("async state transition. not waiting for state complete.\n");
3005 return MM_ERROR_NONE;
3008 /* wait for state transition */
3009 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3011 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3012 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3013 GST_ELEMENT_NAME(element),
3014 gst_element_state_get_name(state), timeout);
3016 LOGE(" [%s] state : %s pending : %s \n",
3017 GST_ELEMENT_NAME(element),
3018 gst_element_state_get_name(element_state),
3019 gst_element_state_get_name(element_pending_state));
3021 /* dump state of all element */
3022 __mmplayer_dump_pipeline_state(player);
3024 return MM_ERROR_PLAYER_INTERNAL;
3027 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3031 return MM_ERROR_NONE;
3034 int __mmplayer_gst_start(mm_player_t* player)
3036 int ret = MM_ERROR_NONE;
3037 gboolean async = FALSE;
3041 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3043 /* NOTE : if SetPosition was called before Start. do it now */
3044 /* streaming doesn't support it. so it should be always sync */
3045 /* !!create one more api to check if there is pending seek rather than checking variables */
3046 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3047 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3048 ret = __mmplayer_gst_pause(player, FALSE);
3049 if (ret != MM_ERROR_NONE) {
3050 LOGE("failed to set state to PAUSED for pending seek");
3054 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3055 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3056 LOGW("failed to seek pending postion. starting from the begin of content");
3059 LOGD("current state before doing transition");
3060 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3061 MMPLAYER_PRINT_STATE(player);
3063 /* set pipeline state to PLAYING */
3064 ret = __mmplayer_gst_set_state(player,
3065 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3067 if (ret == MM_ERROR_NONE) {
3068 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3070 LOGE("failed to set state to PLAYING");
3074 /* generating debug info before returning error */
3075 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3082 int __mmplayer_gst_stop(mm_player_t* player)
3084 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3085 MMHandleType attrs = 0;
3086 gboolean rewind = FALSE;
3088 int ret = MM_ERROR_NONE;
3092 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3093 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3095 LOGD("current state before doing transition");
3096 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3097 MMPLAYER_PRINT_STATE(player);
3099 attrs = MMPLAYER_GET_ATTRS(player);
3101 LOGE("cannot get content attribute\n");
3102 return MM_ERROR_PLAYER_INTERNAL;
3105 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3106 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3108 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3109 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3112 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3113 /* disable the async state transition because there could be no data in the pipeline */
3114 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3118 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3120 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3121 /* enable the async state transition as default operation */
3122 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3125 /* return if set_state has failed */
3126 if (ret != MM_ERROR_NONE) {
3127 LOGE("failed to set state.\n");
3133 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3134 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3135 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3136 LOGW("failed to rewind\n");
3137 ret = MM_ERROR_PLAYER_SEEK;
3142 player->sent_bos = FALSE;
3144 if (player->es_player_push_mode) //for cloudgame
3147 /* wait for seek to complete */
3148 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3149 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3150 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3152 LOGE("fail to stop player.\n");
3153 ret = MM_ERROR_PLAYER_INTERNAL;
3154 __mmplayer_dump_pipeline_state(player);
3157 /* generate dot file if enabled */
3158 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3165 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3167 int ret = MM_ERROR_NONE;
3171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3172 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3174 LOGD("current state before doing transition");
3175 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3176 MMPLAYER_PRINT_STATE(player);
3178 /* set pipeline status to PAUSED */
3179 ret = __mmplayer_gst_set_state(player,
3180 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3182 if (FALSE == async) {
3183 if (ret != MM_ERROR_NONE) {
3184 GstMessage *msg = NULL;
3185 GTimer *timer = NULL;
3186 gdouble MAX_TIMEOUT_SEC = 3;
3188 LOGE("failed to set state to PAUSED");
3190 if (!player->bus_watcher) {
3191 LOGE("there is no bus msg thread. pipeline is shutting down.");
3195 if (player->msg_posted) {
3196 LOGE("error msg is already posted.");
3200 timer = g_timer_new();
3201 g_timer_start(timer);
3203 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3206 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3208 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3209 GError *error = NULL;
3211 /* parse error code */
3212 gst_message_parse_error(msg, &error, NULL);
3214 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3215 /* Note : the streaming error from the streaming source is handled
3216 * using __mmplayer_handle_streaming_error.
3218 __mmplayer_handle_streaming_error(player, msg);
3221 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3223 if (error->domain == GST_STREAM_ERROR)
3224 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3225 else if (error->domain == GST_RESOURCE_ERROR)
3226 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3227 else if (error->domain == GST_LIBRARY_ERROR)
3228 ret = __mmplayer_gst_handle_library_error(player, error->code);
3229 else if (error->domain == GST_CORE_ERROR)
3230 ret = __mmplayer_gst_handle_core_error(player, error->code);
3232 g_error_free(error);
3234 player->msg_posted = TRUE;
3236 gst_message_unref(msg);
3238 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3240 gst_object_unref(bus);
3241 g_timer_stop(timer);
3242 g_timer_destroy(timer);
3246 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3247 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3249 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3252 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3256 /* generate dot file before returning error */
3257 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3264 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3266 int ret = MM_ERROR_NONE;
3271 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3272 MM_ERROR_PLAYER_NOT_INITIALIZED);
3274 LOGD("current state before doing transition");
3275 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3276 MMPLAYER_PRINT_STATE(player);
3279 LOGD("do async state transition to PLAYING");
3281 /* set pipeline state to PLAYING */
3282 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3284 ret = __mmplayer_gst_set_state(player,
3285 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3286 if (ret != MM_ERROR_NONE) {
3287 LOGE("failed to set state to PLAYING");
3291 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3295 /* generate dot file */
3296 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3303 /* sending event to one of sinkelements */
3305 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3307 GstEvent * event2 = NULL;
3308 GList *sinks = NULL;
3309 gboolean res = FALSE;
3312 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3313 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3315 /* While adding subtitles in live feeds seek is getting called.
3316 Adding defensive check in framework layer.*/
3317 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3318 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3319 LOGE("Should not send seek event during live playback");
3324 if (player->play_subtitle)
3325 event2 = gst_event_copy((const GstEvent *)event);
3327 sinks = player->sink_elements;
3329 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3331 if (GST_IS_ELEMENT(sink)) {
3332 /* keep ref to the event */
3333 gst_event_ref(event);
3335 if ((res = gst_element_send_event(sink, event))) {
3336 LOGD("sending event[%s] to sink element [%s] success!\n",
3337 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3339 /* rtsp case, asyn_done is not called after seek during pause state */
3340 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3341 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3342 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3343 LOGD("RTSP seek completed, after pause state..\n");
3344 player->seek_state = MMPLAYER_SEEK_NONE;
3345 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3351 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3352 sinks = g_list_next(sinks);
3359 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3360 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3363 sinks = g_list_next(sinks);
3366 /* Note : Textbin is not linked to the video or audio bin.
3367 * It needs to send the event to the text sink seperatelly.
3369 if (player->play_subtitle && player->pipeline) {
3370 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3372 if (GST_IS_ELEMENT(text_sink)) {
3373 /* keep ref to the event */
3374 gst_event_ref(event2);
3376 if ((res = gst_element_send_event(text_sink, event2)))
3377 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3378 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3380 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3381 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3383 gst_event_unref(event2);
3387 gst_event_unref(event);
3395 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3396 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3397 gint64 cur, GstSeekType stop_type, gint64 stop)
3399 GstEvent* event = NULL;
3400 gboolean result = FALSE;
3404 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3406 if (player->pipeline && player->pipeline->textbin)
3407 __mmplayer_drop_subtitle(player, FALSE);
3409 event = gst_event_new_seek(rate, format, flags, cur_type,
3410 cur, stop_type, stop);
3412 result = __mmplayer_gst_send_event_to_sink(player, event);
3420 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3422 int ret = MM_ERROR_NONE;
3423 gint64 pos_nsec = 0;
3424 gboolean accurated = FALSE;
3425 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3428 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3429 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3431 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3432 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3435 ret = __mmplayer_gst_check_duration(player, position);
3436 if (ret != MM_ERROR_NONE) {
3437 LOGE("failed to check duration 0x%X", ret);
3438 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3441 if (!__mmplayer_gst_check_seekable(player))
3442 return MM_ERROR_PLAYER_NO_OP;
3444 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3445 position, player->playback_rate, player->duration);
3447 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3448 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3449 This causes problem is position calculation during normal pause resume scenarios also.
3450 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3451 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3452 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3453 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3454 LOGW("getting current position failed in seek");
3456 player->last_position = pos_nsec;
3457 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3460 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3461 LOGD("not completed seek");
3462 return MM_ERROR_PLAYER_DOING_SEEK;
3465 if (!internal_called)
3466 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3468 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3469 that's why set position through property. */
3470 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3471 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3472 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3473 (!player->videodec_linked) && (!player->audiodec_linked)) {
3475 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3476 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3478 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3479 player->seek_state = MMPLAYER_SEEK_NONE;
3480 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3482 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3484 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3486 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3488 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3489 GST_FORMAT_TIME, seek_flags,
3490 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3491 LOGE("failed to set position");
3496 /* NOTE : store last seeking point to overcome some bad operation
3497 * (returning zero when getting current position) of some elements
3499 player->last_position = position;
3501 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3502 if (player->playback_rate > 1.0)
3503 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3505 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3506 LOGD("buffering should be reset after seeking");
3507 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3508 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3512 return MM_ERROR_NONE;
3515 player->pending_seek.is_pending = TRUE;
3516 player->pending_seek.pos = position;
3518 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3519 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3520 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3521 player->pending_seek.pos);
3523 return MM_ERROR_NONE;
3526 player->seek_state = MMPLAYER_SEEK_NONE;
3527 return MM_ERROR_PLAYER_SEEK;
3531 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3533 #define TRICKPLAY_OFFSET GST_MSECOND
3535 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3536 gint64 pos_nsec = 0;
3537 gboolean ret = TRUE;
3539 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3540 MM_ERROR_PLAYER_NOT_INITIALIZED);
3542 current_state = MMPLAYER_CURRENT_STATE(player);
3544 /* NOTE : query position except paused state to overcome some bad operation
3545 * please refer to below comments in details
3547 if (current_state != MM_PLAYER_STATE_PAUSED)
3548 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3550 /* NOTE : get last point to overcome some bad operation of some elements
3551 *(returning zero when getting current position in paused state
3552 * and when failed to get postion during seeking
3554 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3555 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3557 if (player->playback_rate < 0.0)
3558 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3560 pos_nsec = player->last_position;
3563 pos_nsec = player->last_position;
3565 player->last_position = pos_nsec;
3567 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3570 if (player->duration > 0 && pos_nsec > player->duration)
3571 pos_nsec = player->duration;
3573 player->last_position = pos_nsec;
3576 *position = pos_nsec;
3578 return MM_ERROR_NONE;
3581 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3583 #define STREAMING_IS_FINISHED 0
3584 #define BUFFERING_MAX_PER 100
3585 #define DEFAULT_PER_VALUE -1
3586 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3588 MMPlayerGstElement *mainbin = NULL;
3589 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3590 gint64 buffered_total = 0;
3591 gint64 position = 0;
3592 gint buffered_sec = -1;
3593 GstBufferingMode mode = GST_BUFFERING_STREAM;
3594 gint64 content_size_time = player->duration;
3595 guint64 content_size_bytes = player->http_content_size;
3597 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3599 player->pipeline->mainbin,
3600 MM_ERROR_PLAYER_NOT_INITIALIZED);
3602 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3607 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3608 /* and rtsp is not ready yet. */
3609 LOGW("it's only used for http streaming case");
3610 return MM_ERROR_PLAYER_NO_OP;
3613 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3614 LOGW("Time format is not supported yet");
3615 return MM_ERROR_INVALID_ARGUMENT;
3618 if (content_size_time <= 0 || content_size_bytes <= 0) {
3619 LOGW("there is no content size");
3620 return MM_ERROR_NONE;
3623 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3624 LOGW("fail to get current position");
3625 return MM_ERROR_NONE;
3628 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3629 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3631 mainbin = player->pipeline->mainbin;
3632 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3634 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3635 GstQuery *query = NULL;
3636 gint byte_in_rate = 0, byte_out_rate = 0;
3637 gint64 estimated_total = 0;
3639 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3640 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3641 LOGW("fail to get buffering query from queue2");
3643 gst_query_unref(query);
3644 return MM_ERROR_NONE;
3647 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3648 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3650 if (mode == GST_BUFFERING_STREAM) {
3651 /* using only queue in case of push mode(ts / mp3) */
3652 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3653 GST_FORMAT_BYTES, &buffered_total)) {
3654 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3655 stop_per = 100 * buffered_total / content_size_bytes;
3658 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3660 guint num_of_ranges = 0;
3661 gint64 start_byte = 0, stop_byte = 0;
3663 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3664 if (estimated_total != STREAMING_IS_FINISHED) {
3665 /* buffered size info from queue2 */
3666 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3667 for (idx = 0; idx < num_of_ranges; idx++) {
3668 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3669 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3671 buffered_total += (stop_byte - start_byte);
3674 stop_per = BUFFERING_MAX_PER;
3676 gst_query_unref(query);
3679 if (stop_per == DEFAULT_PER_VALUE) {
3680 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3682 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3684 /* buffered size info from multiqueue */
3685 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3686 guint curr_size_bytes = 0;
3687 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3688 "curr-size-bytes", &curr_size_bytes, NULL);
3689 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3690 buffered_total += curr_size_bytes;
3693 if (avg_byterate > 0)
3694 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3695 else if (player->total_maximum_bitrate > 0)
3696 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3697 else if (player->total_bitrate > 0)
3698 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3700 if (buffered_sec >= 0)
3701 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3705 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3706 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3708 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3709 buffered_total, buffered_sec, *start_pos, *stop_pos);
3711 return MM_ERROR_NONE;
3714 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3716 GstElement* element = NULL;
3719 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3720 player->pipeline->mainbin, NULL);
3722 /* setup source for gapless play */
3723 switch (player->profile.uri_type) {
3725 case MM_PLAYER_URI_TYPE_FILE:
3726 element = __mmplayer_gst_make_file_src(player);
3728 case MM_PLAYER_URI_TYPE_URL_HTTP:
3729 element = __mmplayer_gst_make_http_src(player);
3732 LOGE("not support uri type %d", player->profile.uri_type);
3737 LOGE("failed to create source element");
3745 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3747 MMHandleType attrs = 0;
3750 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3751 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3753 /* get profile attribute */
3754 attrs = MMPLAYER_GET_ATTRS(player);
3756 LOGE("failed to get content attribute");
3757 return MM_ERROR_PLAYER_INTERNAL;
3760 SECURE_LOGD("uri : %s", player->profile.uri);
3762 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3763 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3764 LOGE("failed to commit");
3766 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3767 return MM_ERROR_PLAYER_INTERNAL;
3769 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3770 return MM_ERROR_PLAYER_INTERNAL;
3772 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3773 return MM_ERROR_PLAYER_INTERNAL;
3776 return MM_ERROR_NONE;
3779 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3781 MMPlayerGstElement *mainbin = NULL;
3782 GstElement *pd_src = NULL;
3783 GstElement *pd_queue = NULL;
3784 GstElement *pd_decodebin = NULL;
3785 GList* element_bucket = NULL;
3786 MMHandleType attrs = 0;
3788 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3791 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3792 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3794 /* get profile attribute */
3795 attrs = MMPLAYER_GET_ATTRS(player);
3797 LOGE("failed to get content attribute");
3798 return MM_ERROR_PLAYER_INTERNAL;
3801 LOGD("http playback with progressive download : %d", player->pd_mode);
3803 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3804 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3805 MMPLAYER_FREEIF(player->pd_file_save_path);
3807 SECURE_LOGD("PD Location : %s", path);
3809 LOGE("filed to find pd location");
3810 return MM_ERROR_PLAYER_INTERNAL;
3813 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3814 LOGE("failed to get storage info");
3815 return MM_ERROR_PLAYER_INTERNAL;
3817 player->pd_file_save_path = g_strdup(path);
3820 pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3822 LOGE("failed to create PD push source");
3823 return MM_ERROR_PLAYER_INTERNAL;
3826 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3827 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3829 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3831 mainbin = player->pipeline->mainbin;
3833 /* take source element */
3834 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3835 mainbin[MMPLAYER_M_SRC].gst = pd_src;
3836 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3839 LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3840 pd_queue = gst_element_factory_make("queue2", "queue2");
3842 LOGE("failed to create pd buffer element");
3847 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3848 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3849 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3851 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3853 player->streamer->is_pd_mode = TRUE;
3855 __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3856 player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3857 player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3859 pd_decodebin = __mmplayer_gst_make_decodebin(player);
3860 if (!pd_decodebin) {
3861 LOGE("failed to create decodebin");
3865 /* default size of mq in decodebin is 2M
3866 * but it can cause blocking issue during seeking depends on content. */
3867 g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3869 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3870 mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3872 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3874 /* add elements to pipeline */
3875 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3876 LOGE("failed to add elements to pipeline");
3880 /* linking elements in the bucket by added order. */
3881 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3882 LOGE("failed to link some elements");
3886 g_list_free(element_bucket);
3889 return MM_ERROR_NONE;
3892 MMPLAYER_FREEIF(player->pd_file_save_path);
3893 g_list_free(element_bucket);
3895 if (mainbin[MMPLAYER_M_SRC].gst)
3896 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3898 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3899 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3901 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3902 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3904 mainbin[MMPLAYER_M_SRC].gst = NULL;
3905 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3906 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3908 return MM_ERROR_PLAYER_INTERNAL;
3911 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3913 MMPlayerGstElement *mainbin = NULL;
3914 GstElement* src_elem = NULL;
3915 GstElement *autoplug_elem = NULL;
3916 GList* element_bucket = NULL;
3917 MMHandleType attrs = 0;
3918 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3921 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3922 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3924 /* get profile attribute */
3925 attrs = MMPLAYER_GET_ATTRS(player);
3927 LOGE("failed to get content attribute");
3928 return MM_ERROR_PLAYER_INTERNAL;
3931 LOGD("uri type %d", player->profile.uri_type);
3933 /* create source element */
3934 switch (player->profile.uri_type) {
3935 case MM_PLAYER_URI_TYPE_URL_RTSP:
3936 src_elem = __mmplayer_gst_make_rtsp_src(player);
3938 case MM_PLAYER_URI_TYPE_URL_HTTP:
3939 src_elem = __mmplayer_gst_make_http_src(player);
3941 case MM_PLAYER_URI_TYPE_FILE:
3942 src_elem = __mmplayer_gst_make_file_src(player);
3944 case MM_PLAYER_URI_TYPE_SS:
3946 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3947 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3949 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3953 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3954 LOGD("get timeout from ini");
3955 http_timeout = player->ini.http_timeout;
3958 /* setting property to streaming source */
3959 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3962 case MM_PLAYER_URI_TYPE_MEM:
3964 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3966 src_elem = gst_element_factory_make("appsrc", "mem-source");
3968 LOGE("failed to create appsrc element");
3972 g_object_set(src_elem, "stream-type", stream_type,
3973 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3975 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3976 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3977 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3978 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3982 LOGE("not support uri type");
3987 LOGE("failed to create source element");
3988 return MM_ERROR_PLAYER_INTERNAL;
3991 mainbin = player->pipeline->mainbin;
3993 /* take source element */
3994 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3996 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3997 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3998 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4000 /* create next element for auto-plugging */
4001 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4002 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4003 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4004 if (!autoplug_elem) {
4005 LOGE("failed to create typefind element");
4009 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4010 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4011 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4012 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4013 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4014 if (!autoplug_elem) {
4015 LOGE("failed to create decodebin");
4019 /* default size of mq in decodebin is 2M
4020 * but it can cause blocking issue during seeking depends on content. */
4021 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4024 if (autoplug_elem) {
4025 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4026 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4027 mainbin[autoplug_elem_id].gst = autoplug_elem;
4029 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4032 /* add elements to pipeline */
4033 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4034 LOGE("failed to add elements to pipeline");
4038 /* linking elements in the bucket by added order. */
4039 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4040 LOGE("failed to link some elements");
4044 /* FIXME: need to check whether this is required or not. */
4045 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4046 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4047 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4048 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4050 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4051 LOGE("failed to create fakesink");
4054 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4056 /* take ownership of fakesink. we are reusing it */
4057 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4059 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4060 LOGE("failed to add fakesink to bin");
4061 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4066 g_list_free(element_bucket);
4069 return MM_ERROR_NONE;
4072 g_list_free(element_bucket);
4074 if (mainbin[MMPLAYER_M_SRC].gst)
4075 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4077 if (mainbin[autoplug_elem_id].gst)
4078 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4080 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4081 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4083 mainbin[MMPLAYER_M_SRC].gst = NULL;
4084 mainbin[autoplug_elem_id].gst = NULL;
4085 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4087 return MM_ERROR_PLAYER_INTERNAL;
4090 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4093 MMPlayerGstElement *mainbin = NULL;
4096 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4097 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4099 mainbin = player->pipeline->mainbin;
4101 /* connect bus callback */
4102 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4104 LOGE("cannot get bus from pipeline");
4105 return MM_ERROR_PLAYER_INTERNAL;
4108 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4109 player->context.thread_default = g_main_context_get_thread_default();
4110 if (player->context.thread_default == NULL) {
4111 player->context.thread_default = g_main_context_default();
4112 LOGD("thread-default context is the global default context");
4114 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4116 /* set sync handler to get tag synchronously */
4117 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4118 gst_object_unref(GST_OBJECT(bus));
4120 /* create gst bus_msb_cb thread */
4121 g_mutex_init(&player->bus_msg_thread_mutex);
4122 g_cond_init(&player->bus_msg_thread_cond);
4123 player->bus_msg_thread_exit = FALSE;
4124 player->bus_msg_thread =
4125 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4126 if (!player->bus_msg_thread) {
4127 LOGE("failed to create gst BUS msg thread");
4128 g_mutex_clear(&player->bus_msg_thread_mutex);
4129 g_cond_clear(&player->bus_msg_thread_cond);
4130 return MM_ERROR_PLAYER_INTERNAL;
4134 return MM_ERROR_NONE;