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"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
87 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
89 /* check whether the error is posted from not-activated track or not */
91 gint active_pad_index = 0;
93 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
95 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
96 LOGD("current active pad index -%d", active_pad_index);
98 if (src_element_name) {
101 if (player->audio_decoders) {
102 GList *adec = player->audio_decoders;
103 for (; adec ; adec = g_list_next(adec)) {
104 gchar *name = adec->data;
106 LOGD("found audio decoder name = %s", name);
107 if (g_strrstr(name, src_element_name)) {
114 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
117 if (active_pad_index != msg_src_pos) {
118 LOGD("skip error because error is posted from no activated track");
126 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
128 /* Demuxer can't parse one track because it's corrupted.
129 * So, the decoder for it is not linked.
130 * But, it has one playable track.
132 if (g_strrstr(klass, "Demux")) {
133 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
134 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
135 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
136 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
138 if (player->pipeline->audiobin) { // PCM
139 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
141 LOGD("not found any available codec. Player should be destroyed.");
142 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
147 return MM_ERROR_PLAYER_INVALID_STREAM;
151 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
153 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
154 LOGE("Not supported subtitle.");
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
157 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
161 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
163 /* Decoder Custom Message */
164 if (!strstr(error->message, "ongoing"))
165 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
167 if (strncasecmp(klass, "audio", 5)) {
168 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
169 LOGD("Video can keep playing.");
170 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
172 } else if (strncasecmp(klass, "video", 5)) {
173 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
174 LOGD("Audio can keep playing.");
175 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
179 LOGD("not found any available codec. Player should be destroyed.");
180 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
184 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
186 if (strstr(error->message, "rights expired"))
187 return MM_ERROR_PLAYER_DRM_EXPIRED;
188 else if (strstr(error->message, "no rights"))
189 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
190 else if (strstr(error->message, "has future rights"))
191 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
192 else if (strstr(error->message, "opl violation"))
193 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
195 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
198 /* NOTE : decide gstreamer state whether there is some playable track or not. */
200 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
202 gchar *src_element_name = NULL;
203 GstElement *src_element = NULL;
204 GstElementFactory *factory = NULL;
205 const gchar *klass = NULL;
209 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
211 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
212 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
214 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
216 src_element = GST_ELEMENT_CAST(message->src);
218 return MM_ERROR_PLAYER_INTERNAL;
220 src_element_name = GST_ELEMENT_NAME(src_element);
221 if (!src_element_name)
222 return MM_ERROR_PLAYER_INTERNAL;
224 factory = gst_element_get_factory(src_element);
226 return MM_ERROR_PLAYER_INTERNAL;
228 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
230 return MM_ERROR_PLAYER_INTERNAL;
232 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
233 error->code, error->message, src_element_name, klass);
235 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
236 return MM_ERROR_NONE;
238 switch (error->code) {
239 case GST_STREAM_ERROR_DECODE:
240 return __mmplayer_gst_transform_error_decode(player, klass);
241 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
242 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
243 case GST_STREAM_ERROR_WRONG_TYPE:
244 return __mmplayer_gst_transform_error_type(player, src_element);
245 case GST_STREAM_ERROR_FAILED:
246 return __mmplayer_gst_transform_error_failed(player, klass, error);
247 case GST_STREAM_ERROR_DECRYPT:
248 case GST_STREAM_ERROR_DECRYPT_NOKEY:
249 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
250 return __mmplayer_gst_transform_error_decrypt(player, error);
257 return MM_ERROR_PLAYER_INVALID_STREAM;
261 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
263 gint trans_err = MM_ERROR_NONE;
267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
270 case GST_CORE_ERROR_MISSING_PLUGIN:
271 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
272 case GST_CORE_ERROR_STATE_CHANGE:
273 case GST_CORE_ERROR_SEEK:
274 case GST_CORE_ERROR_NOT_IMPLEMENTED:
275 case GST_CORE_ERROR_FAILED:
276 case GST_CORE_ERROR_TOO_LAZY:
277 case GST_CORE_ERROR_PAD:
278 case GST_CORE_ERROR_THREAD:
279 case GST_CORE_ERROR_NEGOTIATION:
280 case GST_CORE_ERROR_EVENT:
281 case GST_CORE_ERROR_CAPS:
282 case GST_CORE_ERROR_TAG:
283 case GST_CORE_ERROR_CLOCK:
284 case GST_CORE_ERROR_DISABLED:
286 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
296 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
298 gint trans_err = MM_ERROR_NONE;
302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
305 case GST_LIBRARY_ERROR_FAILED:
306 case GST_LIBRARY_ERROR_TOO_LAZY:
307 case GST_LIBRARY_ERROR_INIT:
308 case GST_LIBRARY_ERROR_SHUTDOWN:
309 case GST_LIBRARY_ERROR_SETTINGS:
310 case GST_LIBRARY_ERROR_ENCODE:
312 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
322 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
324 gint trans_err = MM_ERROR_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
331 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
332 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
334 case GST_RESOURCE_ERROR_NOT_FOUND:
335 case GST_RESOURCE_ERROR_OPEN_READ:
336 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
337 || MMPLAYER_IS_RTSP_STREAMING(player)) {
338 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
341 case GST_RESOURCE_ERROR_READ:
342 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
343 || MMPLAYER_IS_RTSP_STREAMING(player)) {
344 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
346 } else if (message != NULL && message->src != NULL) {
347 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
348 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
350 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
351 path_type = MMPLAYER_PATH_VOD;
352 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
353 path_type = MMPLAYER_PATH_TEXT;
355 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
356 /* check storage state */
357 storage_get_state(player->storage_info[path_type].id, &storage_state);
358 player->storage_info[path_type].state = storage_state;
359 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
362 case GST_RESOURCE_ERROR_WRITE:
363 case GST_RESOURCE_ERROR_FAILED:
364 case GST_RESOURCE_ERROR_SEEK:
365 case GST_RESOURCE_ERROR_TOO_LAZY:
366 case GST_RESOURCE_ERROR_BUSY:
367 case GST_RESOURCE_ERROR_OPEN_WRITE:
368 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
369 case GST_RESOURCE_ERROR_CLOSE:
370 case GST_RESOURCE_ERROR_SYNC:
371 case GST_RESOURCE_ERROR_SETTINGS:
373 trans_err = MM_ERROR_PLAYER_INTERNAL;
383 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
385 gint trans_err = MM_ERROR_NONE;
389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
390 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
391 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
393 switch (error->code) {
394 case GST_STREAM_ERROR_FAILED:
395 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
396 case GST_STREAM_ERROR_DECODE:
397 case GST_STREAM_ERROR_WRONG_TYPE:
398 case GST_STREAM_ERROR_DECRYPT:
399 case GST_STREAM_ERROR_DECRYPT_NOKEY:
400 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
401 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
404 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
405 case GST_STREAM_ERROR_TOO_LAZY:
406 case GST_STREAM_ERROR_ENCODE:
407 case GST_STREAM_ERROR_DEMUX:
408 case GST_STREAM_ERROR_MUX:
409 case GST_STREAM_ERROR_FORMAT:
411 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
421 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
423 MMMessageParamType msg_param;
424 gchar *msg_src_element;
428 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
429 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
431 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
433 memset(&msg_param, 0, sizeof(MMMessageParamType));
435 if (error->domain == GST_CORE_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
437 } else if (error->domain == GST_LIBRARY_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
439 } else if (error->domain == GST_RESOURCE_ERROR) {
440 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
441 } else if (error->domain == GST_STREAM_ERROR) {
442 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
444 LOGW("This error domain is not defined.");
446 /* we treat system error as an internal error */
447 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
451 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
453 msg_param.data = (void *)error->message;
455 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
456 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
460 if (msg_param.code == MM_ERROR_NONE)
463 /* skip error to avoid duplicated posting */
464 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
465 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
466 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
467 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
469 /* The error will be handled by mused.
470 * @ref _mmplayer_manage_external_storage_state() */
472 LOGW("storage is removed, skip error post");
476 /* post error to application */
477 if (!player->msg_posted) {
478 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
479 /* don't post more if one was sent already */
480 player->msg_posted = TRUE;
482 LOGD("skip error post because it's sent already.");
491 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
494 MMMessageParamType msg_param;
495 gchar *msg_src_element = NULL;
496 GstStructure *s = NULL;
498 gchar *error_string = NULL;
502 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
503 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
505 s = gst_structure_copy(gst_message_get_structure(message));
508 if (!gst_structure_get_uint(s, "error_id", &error_id))
509 error_id = MMPLAYER_STREAMING_ERROR_NONE;
512 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
515 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
518 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
521 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
524 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
527 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
530 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
533 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
536 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
539 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
542 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
545 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
548 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
551 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
554 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
557 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
560 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
563 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
566 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
569 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
572 case MMPLAYER_STREAMING_ERROR_GONE:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
575 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
578 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
581 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
584 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
587 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
590 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
593 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
596 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
599 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
602 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
605 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
608 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
611 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
614 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
617 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
620 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
623 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
626 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
629 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
632 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
635 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
636 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
638 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
639 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
641 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
642 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
644 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
645 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
649 gst_structure_free(s);
650 return MM_ERROR_PLAYER_STREAMING_FAIL;
654 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
656 msg_param.data = (void *)error_string;
659 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
661 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]",
662 msg_src_element, msg_param.code, (char *)msg_param.data);
665 /* post error to application */
666 if (!player->msg_posted) {
667 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
669 /* don't post more if one was sent already */
670 player->msg_posted = TRUE;
672 LOGD("skip error post because it's sent already.");
675 gst_structure_free(s);
676 MMPLAYER_FREEIF(error_string);
684 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
686 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
687 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
688 gst_tag_list_get_string(tags, "stitching_software",
689 &metadata->stitching_software);
690 gst_tag_list_get_string(tags, "projection_type",
691 &metadata->projection_type_string);
692 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
693 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
694 gst_tag_list_get_int(tags, "init_view_heading",
695 &metadata->init_view_heading);
696 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
697 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
698 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
699 gst_tag_list_get_int(tags, "full_pano_width_pixels",
700 &metadata->full_pano_width_pixels);
701 gst_tag_list_get_int(tags, "full_pano_height_pixels",
702 &metadata->full_pano_height_pixels);
703 gst_tag_list_get_int(tags, "cropped_area_image_width",
704 &metadata->cropped_area_image_width);
705 gst_tag_list_get_int(tags, "cropped_area_image_height",
706 &metadata->cropped_area_image_height);
707 gst_tag_list_get_int(tags, "cropped_area_left",
708 &metadata->cropped_area_left);
709 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
710 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
711 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
712 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
716 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
719 /* macro for better code readability */
720 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
722 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
723 if (string != NULL) { \
724 SECURE_LOGD("update tag string : %s", string); \
725 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
726 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
727 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
728 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
729 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
730 MMPLAYER_FREEIF(new_string); \
732 mm_attrs_set_string_by_name(attribute, playertag, string); \
734 MMPLAYER_FREEIF(string); \
739 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
741 GstSample *sample = NULL;\
742 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
743 GstMapInfo info = GST_MAP_INFO_INIT;\
744 buffer = gst_sample_get_buffer(sample);\
745 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
746 LOGD("failed to get image data from tag");\
747 gst_sample_unref(sample);\
750 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
751 MMPLAYER_FREEIF(player->album_art);\
752 player->album_art = (gchar *)g_malloc(info.size);\
753 if (player->album_art) {\
754 memcpy(player->album_art, info.data, info.size);\
755 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
756 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
757 msg_param.data = (void *)player->album_art;\
758 msg_param.size = info.size;\
759 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
760 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
763 gst_buffer_unmap(buffer, &info);\
764 gst_sample_unref(sample);\
768 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
770 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
773 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
774 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
775 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
776 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
777 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
779 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
780 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
781 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
782 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
783 player->bitrate[track_type] = v_uint; \
784 player->total_bitrate = 0; \
785 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
786 player->total_bitrate += player->bitrate[i]; \
787 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
788 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
789 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
790 player->maximum_bitrate[track_type] = v_uint; \
791 player->total_maximum_bitrate = 0; \
792 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
793 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
794 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
795 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
797 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
804 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
806 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
808 string = g_strdup_printf("%d", g_date_get_year(date));\
809 mm_attrs_set_string_by_name(attribute, playertag, string);\
810 SECURE_LOGD("metainfo year : %s", string);\
811 MMPLAYER_FREEIF(string);\
817 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
820 if (datetime != NULL) {\
821 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
822 mm_attrs_set_string_by_name(attribute, playertag, string);\
823 SECURE_LOGD("metainfo year : %s", string);\
824 MMPLAYER_FREEIF(string);\
825 gst_date_time_unref(datetime);\
830 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
832 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
834 /* FIXIT : don't know how to store date */\
841 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
843 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
845 /* FIXIT : don't know how to store date */\
853 GstTagList *tag_list = NULL;
855 MMHandleType attrs = 0;
860 GstDateTime *datetime = NULL;
862 GstBuffer *buffer = NULL;
864 MMMessageParamType msg_param = {0, };
866 /* currently not used. but those are needed for above macro */
867 //guint64 v_uint64 = 0;
868 //gdouble v_double = 0;
870 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
872 attrs = MMPLAYER_GET_ATTRS(player);
874 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
876 /* get tag list from gst message */
877 gst_message_parse_tag(msg, &tag_list);
879 /* store tags to player attributes */
880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
882 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
887 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
888 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
892 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
898 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
901 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
904 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
905 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
907 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
909 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
910 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
911 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
912 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
913 MMPLAYER_UPDATE_TAG_LOCK(player);
914 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
915 MMPLAYER_UPDATE_TAG_UNLOCK(player);
916 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
917 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
918 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
920 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
921 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
922 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
923 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
924 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
925 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
927 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
930 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
931 if (player->video360_metadata.is_spherical == -1) {
932 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
933 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
934 player->video360_metadata.is_spherical);
935 if (player->video360_metadata.is_spherical == 1) {
936 LOGD("This is spherical content for 360 playback.");
937 player->is_content_spherical = TRUE;
939 LOGD("This is not spherical content");
940 player->is_content_spherical = FALSE;
943 if (player->video360_metadata.projection_type_string) {
944 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
945 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
947 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
948 player->is_content_spherical = player->is_video360_enabled = FALSE;
952 if (player->video360_metadata.stereo_mode_string) {
953 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
954 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
955 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
956 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
957 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
958 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
960 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
961 player->is_content_spherical = player->is_video360_enabled = FALSE;
967 if (mm_attrs_commit_all(attrs))
968 LOGE("failed to commit.");
970 gst_tag_list_unref(tag_list);
975 /* if retval is FALSE, it will be dropped for perfomance. */
977 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
979 gboolean retval = FALSE;
981 if (!(player->pipeline && player->pipeline->mainbin)) {
982 LOGE("player pipeline handle is null");
986 switch (GST_MESSAGE_TYPE(message)) {
987 case GST_MESSAGE_TAG:
988 case GST_MESSAGE_EOS:
989 case GST_MESSAGE_ERROR:
990 case GST_MESSAGE_WARNING:
991 case GST_MESSAGE_CLOCK_LOST:
992 case GST_MESSAGE_NEW_CLOCK:
993 case GST_MESSAGE_ELEMENT:
994 case GST_MESSAGE_DURATION_CHANGED:
995 case GST_MESSAGE_ASYNC_START:
998 case GST_MESSAGE_ASYNC_DONE:
999 case GST_MESSAGE_STATE_CHANGED:
1000 /* we only handle messages from pipeline */
1001 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
1006 case GST_MESSAGE_BUFFERING:
1008 gint buffer_percent = 0;
1011 gst_message_parse_buffering(message, &buffer_percent);
1012 if (buffer_percent != MAX_BUFFER_PERCENT) {
1013 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1017 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1018 LOGW("can't get cmd lock, send msg to bus");
1022 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1023 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1024 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1027 MMPLAYER_CMD_UNLOCK(player);
1040 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1042 guint64 data_size = 0;
1043 gint64 pos_nsec = 0;
1045 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1047 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1049 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1050 data_size = player->http_content_size;
1053 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1054 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1060 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1062 int ret = MM_ERROR_NONE;
1063 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1064 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1065 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1066 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1068 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1069 LOGW("do nothing for buffering msg");
1070 ret = MM_ERROR_PLAYER_INVALID_STATE;
1074 prev_state = MMPLAYER_PREV_STATE(player);
1075 current_state = MMPLAYER_CURRENT_STATE(player);
1076 target_state = MMPLAYER_TARGET_STATE(player);
1077 pending_state = MMPLAYER_PENDING_STATE(player);
1079 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1080 MMPLAYER_STATE_GET_NAME(prev_state),
1081 MMPLAYER_STATE_GET_NAME(current_state),
1082 MMPLAYER_STATE_GET_NAME(pending_state),
1083 MMPLAYER_STATE_GET_NAME(target_state),
1084 player->streamer->buffering_state);
1086 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1087 /* NOTE : if buffering has done, player has to go to target state. */
1088 switch (target_state) {
1089 case MM_PLAYER_STATE_PAUSED:
1091 switch (pending_state) {
1092 case MM_PLAYER_STATE_PLAYING:
1093 __mmplayer_gst_pause(player, TRUE);
1096 case MM_PLAYER_STATE_PAUSED:
1097 LOGD("player is already going to paused state, there is nothing to do.");
1100 case MM_PLAYER_STATE_NONE:
1101 case MM_PLAYER_STATE_NULL:
1102 case MM_PLAYER_STATE_READY:
1104 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1110 case MM_PLAYER_STATE_PLAYING:
1112 switch (pending_state) {
1113 case MM_PLAYER_STATE_NONE:
1115 if (current_state != MM_PLAYER_STATE_PLAYING)
1116 __mmplayer_gst_resume(player, TRUE);
1120 case MM_PLAYER_STATE_PAUSED:
1121 /* NOTE: It should be worked as asynchronously.
1122 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1124 if (current_state == MM_PLAYER_STATE_PLAYING) {
1125 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1126 * The current state should be changed to paused purposely to prevent state conflict.
1128 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1130 __mmplayer_gst_resume(player, TRUE);
1133 case MM_PLAYER_STATE_PLAYING:
1134 LOGD("player is already going to playing state, there is nothing to do.");
1137 case MM_PLAYER_STATE_NULL:
1138 case MM_PLAYER_STATE_READY:
1140 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1146 case MM_PLAYER_STATE_NULL:
1147 case MM_PLAYER_STATE_READY:
1148 case MM_PLAYER_STATE_NONE:
1150 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1154 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1155 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1157 switch (pending_state) {
1158 case MM_PLAYER_STATE_NONE:
1160 if (current_state != MM_PLAYER_STATE_PAUSED) {
1161 /* rtsp streaming pause makes rtsp server stop sending data. */
1162 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1163 LOGD("set pause state during buffering");
1164 __mmplayer_gst_pause(player, TRUE);
1170 case MM_PLAYER_STATE_PLAYING:
1171 /* rtsp streaming pause makes rtsp server stop sending data. */
1172 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1173 __mmplayer_gst_pause(player, TRUE);
1176 case MM_PLAYER_STATE_PAUSED:
1179 case MM_PLAYER_STATE_NULL:
1180 case MM_PLAYER_STATE_READY:
1182 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1191 static stream_variant_t *
1192 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1194 stream_variant_t *var_info = NULL;
1195 g_return_val_if_fail(self != NULL, NULL);
1197 var_info = g_new0(stream_variant_t, 1);
1198 if (!var_info) return NULL;
1199 var_info->bandwidth = self->bandwidth;
1200 var_info->width = self->width;
1201 var_info->height = self->height;
1206 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1212 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1213 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1215 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1216 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1217 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1219 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1220 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1221 player->http_content_size = (bytes > 0) ? bytes : 0;
1224 /* handling audio clip which has vbr. means duration is keep changing */
1225 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1234 __mmplayer_eos_timer_cb(gpointer u_data)
1236 mmplayer_t *player = NULL;
1237 MMHandleType attrs = 0;
1240 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1242 player = (mmplayer_t *)u_data;
1243 attrs = MMPLAYER_GET_ATTRS(player);
1245 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1249 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1250 if (ret_value != MM_ERROR_NONE)
1251 LOGE("seeking to 0 failed in repeat play");
1254 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1257 /* we are returning FALSE as we need only one posting */
1262 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1264 MMPLAYER_RETURN_IF_FAIL(player);
1266 /* post now if delay is zero */
1267 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1268 LOGD("eos delay is zero. posting EOS now");
1269 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1271 if (player->audio_decoded_cb)
1272 __mmplayer_cancel_eos_timer(player);
1277 /* cancel if existing */
1278 __mmplayer_cancel_eos_timer(player);
1280 /* init new timeout */
1281 /* NOTE : consider give high priority to this timer */
1282 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1284 player->eos_timer = g_timeout_add(delay_in_ms,
1285 __mmplayer_eos_timer_cb, player);
1287 player->context.global_default = g_main_context_default();
1288 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1290 /* check timer is valid. if not, send EOS now */
1291 if (player->eos_timer == 0) {
1292 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1293 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1298 __mmplayer_gst_pending_seek(mmplayer_t *player)
1300 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1301 int ret = MM_ERROR_NONE;
1305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1307 if (!player->pending_seek.is_pending) {
1308 LOGD("pending seek is not reserved. nothing to do.");
1312 /* check player state if player could pending seek or not. */
1313 current_state = MMPLAYER_CURRENT_STATE(player);
1315 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1316 LOGW("try to pending seek in %s state, try next time. ",
1317 MMPLAYER_STATE_GET_NAME(current_state));
1321 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1323 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1324 if (ret != MM_ERROR_NONE)
1325 LOGE("failed to seek pending postion. just keep staying current position.");
1327 player->pending_seek.is_pending = false;
1335 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1337 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1339 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1341 audiobin = player->pipeline->audiobin; /* can be null */
1342 videobin = player->pipeline->videobin; /* can be null */
1343 textbin = player->pipeline->textbin; /* can be null */
1345 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1347 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1348 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1350 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1351 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1353 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1354 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1360 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1362 mmplayer_gst_element_t *textbin;
1365 MMPLAYER_RETURN_IF_FAIL(player &&
1367 player->pipeline->textbin);
1369 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1371 textbin = player->pipeline->textbin;
1374 LOGD("Drop subtitle text after getting EOS");
1376 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1377 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1379 player->is_subtitle_force_drop = TRUE;
1381 if (player->is_subtitle_force_drop == TRUE) {
1382 LOGD("Enable subtitle data path without drop");
1384 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1385 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1387 LOGD("non-connected with external display");
1389 player->is_subtitle_force_drop = FALSE;
1395 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1397 MMHandleType attrs = 0;
1402 /* NOTE : EOS event is comming multiple time. watch out it */
1403 /* check state. we only process EOS when pipeline state goes to PLAYING */
1404 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1405 LOGD("EOS received on non-playing state. ignoring it");
1409 if (player->pipeline && player->pipeline->textbin)
1410 __mmplayer_drop_subtitle(player, TRUE);
1412 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1413 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1415 /* rewind if repeat count is greater then zero */
1416 /* get play count */
1417 attrs = MMPLAYER_GET_ATTRS(player);
1419 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1421 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1423 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1424 if (player->playback_rate < 0.0) {
1425 player->resumed_by_rewind = TRUE;
1426 _mmplayer_set_mute((MMHandleType)player, 0);
1427 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1430 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1433 player->sent_bos = FALSE;
1435 LOGD("do not post eos msg for repeating");
1440 if (player->pipeline)
1441 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1443 /* post eos message to application */
1444 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1446 /* reset last position */
1447 player->last_position = 0;
1454 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1456 GError *error = NULL;
1457 gchar *debug = NULL;
1461 /* generating debug info before returning error */
1462 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1464 /* get error code */
1465 gst_message_parse_error(msg, &error, &debug);
1467 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1468 /* Note : the streaming error from the streaming source is handled
1469 * using __mmplayer_handle_streaming_error.
1471 __mmplayer_handle_streaming_error(player, msg);
1473 /* dump state of all element */
1474 __mmplayer_dump_pipeline_state(player);
1476 /* traslate gst error code to msl error code. then post it
1477 * to application if needed
1479 __mmplayer_handle_gst_error(player, msg, error);
1482 LOGE("error debug : %s", debug);
1485 MMPLAYER_FREEIF(debug);
1486 g_error_free(error);
1493 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1495 MMMessageParamType msg_param = {0, };
1496 int bRet = MM_ERROR_NONE;
1499 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1501 if (!MMPLAYER_IS_STREAMING(player)) {
1502 LOGW("this is not streaming playback.");
1506 MMPLAYER_CMD_LOCK(player);
1508 if (!player->streamer) {
1509 LOGW("Pipeline is shutting down");
1510 MMPLAYER_CMD_UNLOCK(player);
1514 /* ignore the remained buffering message till getting 100% msg */
1515 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1516 gint buffer_percent = 0;
1518 gst_message_parse_buffering(msg, &buffer_percent);
1520 if (buffer_percent == MAX_BUFFER_PERCENT) {
1521 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1522 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1523 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1525 MMPLAYER_CMD_UNLOCK(player);
1529 /* ignore the remained buffering message */
1530 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1531 gint buffer_percent = 0;
1533 gst_message_parse_buffering(msg, &buffer_percent);
1535 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1536 player->streamer->buffering_percent, buffer_percent);
1538 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1539 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1540 player->streamer->buffering_req.is_pre_buffering = FALSE;
1542 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1544 LOGD("interrupted buffering - ignored the remained buffering msg!");
1545 MMPLAYER_CMD_UNLOCK(player);
1550 __mmplayer_update_buffer_setting(player, msg);
1552 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1554 if (bRet == MM_ERROR_NONE) {
1555 msg_param.connection.buffering = player->streamer->buffering_percent;
1556 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1558 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1559 player->pending_resume &&
1560 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1562 player->is_external_subtitle_added_now = FALSE;
1563 player->pending_resume = FALSE;
1564 _mmplayer_resume((MMHandleType)player);
1567 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1568 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1570 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1571 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1572 player->seek_state = MMPLAYER_SEEK_NONE;
1573 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1574 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1575 /* Considering the async state trasition in case of RTSP.
1576 After getting state change gst msg, seek cmpleted msg will be posted. */
1577 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1581 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1582 if (!player->streamer) {
1583 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1584 MMPLAYER_CMD_UNLOCK(player);
1588 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1590 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1591 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1593 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1594 msg_param.connection.buffering = player->streamer->buffering_percent;
1595 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1597 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1600 msg_param.connection.buffering = player->streamer->buffering_percent;
1601 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1604 MMPLAYER_CMD_UNLOCK(player);
1612 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1614 mmplayer_gst_element_t *mainbin;
1615 const GValue *voldstate, *vnewstate, *vpending;
1616 GstState oldstate = GST_STATE_NULL;
1617 GstState newstate = GST_STATE_NULL;
1618 GstState pending = GST_STATE_NULL;
1621 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1623 mainbin = player->pipeline->mainbin;
1625 /* we only handle messages from pipeline */
1626 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1629 /* get state info from msg */
1630 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1631 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1632 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1634 if (!voldstate || !vnewstate) {
1635 LOGE("received msg has wrong format.");
1639 oldstate = (GstState)voldstate->data[0].v_int;
1640 newstate = (GstState)vnewstate->data[0].v_int;
1642 pending = (GstState)vpending->data[0].v_int;
1644 LOGD("state changed [%s] : %s ---> %s final : %s",
1645 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1646 gst_element_state_get_name((GstState)oldstate),
1647 gst_element_state_get_name((GstState)newstate),
1648 gst_element_state_get_name((GstState)pending));
1650 if (newstate == GST_STATE_PLAYING) {
1651 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1653 int retVal = MM_ERROR_NONE;
1654 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1656 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1658 if (MM_ERROR_NONE != retVal)
1659 LOGE("failed to seek pending postion. just keep staying current position.");
1661 player->pending_seek.is_pending = false;
1665 if (oldstate == newstate) {
1666 LOGD("pipeline reports state transition to old state");
1671 case GST_STATE_PAUSED:
1673 gboolean prepare_async = FALSE;
1675 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1676 // managed prepare async case
1677 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1678 LOGD("checking prepare mode for async transition - %d", prepare_async);
1681 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1682 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1684 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1685 __mm_player_streaming_set_content_bitrate(player->streamer,
1686 player->total_maximum_bitrate, player->total_bitrate);
1688 if (player->pending_seek.is_pending) {
1689 LOGW("trying to do pending seek");
1690 MMPLAYER_CMD_LOCK(player);
1691 __mmplayer_gst_pending_seek(player);
1692 MMPLAYER_CMD_UNLOCK(player);
1698 case GST_STATE_PLAYING:
1700 if (MMPLAYER_IS_STREAMING(player)) {
1701 // managed prepare async case when buffering is completed
1702 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1703 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1704 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1705 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1707 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1709 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1710 if (player->streamer->buffering_percent < 100) {
1712 MMMessageParamType msg_param = {0, };
1713 LOGW("Posting Buffering Completed Message to Application !!!");
1715 msg_param.connection.buffering = 100;
1716 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1721 if (player->gapless.stream_changed) {
1722 __mmplayer_update_content_attrs(player, ATTR_ALL);
1723 player->gapless.stream_changed = FALSE;
1726 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1727 player->seek_state = MMPLAYER_SEEK_NONE;
1728 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1732 case GST_STATE_VOID_PENDING:
1733 case GST_STATE_NULL:
1734 case GST_STATE_READY:
1744 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1746 const gchar *structure_name;
1747 gint count = 0, idx = 0;
1748 MMHandleType attrs = 0;
1751 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1753 attrs = MMPLAYER_GET_ATTRS(player);
1755 LOGE("Failed to get content attribute");
1759 if (gst_message_get_structure(msg) == NULL)
1762 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1763 if (!structure_name)
1766 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1768 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1769 const GValue *var_info = NULL;
1771 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1772 if (var_info != NULL) {
1773 if (player->adaptive_info.var_list)
1774 g_list_free_full(player->adaptive_info.var_list, g_free);
1776 /* share addr or copy the list */
1777 player->adaptive_info.var_list =
1778 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1780 count = g_list_length(player->adaptive_info.var_list);
1782 stream_variant_t *temp = NULL;
1784 /* print out for debug */
1785 LOGD("num of variant_info %d", count);
1786 for (idx = 0; idx < count; idx++) {
1787 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1789 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1795 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1796 gint num_buffers = 0;
1797 gint extra_num_buffers = 0;
1799 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1800 player->video_num_buffers = num_buffers;
1801 LOGD("video_num_buffers : %d", player->video_num_buffers);
1804 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1805 player->video_extra_num_buffers = extra_num_buffers;
1806 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1811 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1812 __mmplayer_track_update_text_attr_info(player, msg);
1814 /* custom message */
1815 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1816 MMMessageParamType msg_param = {0,};
1817 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1818 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1821 /* custom message for RTSP attribute :
1822 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1823 sdp which has contents info is received when rtsp connection is opened.
1824 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1825 if (!strcmp(structure_name, "rtspsrc_properties")) {
1826 gchar *audio_codec = NULL;
1827 gchar *video_codec = NULL;
1828 gchar *video_frame_size = NULL;
1830 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1831 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1832 player->streaming_type = __mmplayer_get_stream_service_type(player);
1834 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1835 LOGD("rtsp_audio_codec : %s", audio_codec);
1837 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1839 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1840 LOGD("rtsp_video_codec : %s", video_codec);
1842 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1844 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1845 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1846 if (video_frame_size) {
1847 char *seperator = strchr(video_frame_size, '-');
1849 char video_width[10] = {0,};
1850 int frame_size_len = strlen(video_frame_size);
1851 int separtor_len = strlen(seperator);
1853 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1854 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1857 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1861 if (mm_attrs_commit_all(attrs))
1862 LOGE("failed to commit.");
1870 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1872 mmplayer_gst_element_t *mainbin;
1875 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1877 mainbin = player->pipeline->mainbin;
1879 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1881 /* we only handle messages from pipeline */
1882 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1885 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1886 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1887 player->seek_state = MMPLAYER_SEEK_NONE;
1888 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1889 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1890 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1891 LOGD("sync %s state(%s) with parent state(%s)",
1892 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1893 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1894 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1896 /* In case of streaming, pause is required before finishing seeking by buffering.
1897 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1898 Because the buffering state is controlled according to the state transition for force resume,
1899 the decodebin state should be paused as player state. */
1900 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1903 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1904 (player->streamer) &&
1905 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1906 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1907 GstQuery *query = NULL;
1908 gboolean busy = FALSE;
1911 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1912 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1913 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1914 gst_query_parse_buffering_percent(query, &busy, &percent);
1915 gst_query_unref(query);
1917 LOGD("buffered percent(%s): %d",
1918 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1922 __mmplayer_handle_buffering_playback(player);
1925 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1934 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1936 mmplayer_t *player = (mmplayer_t *)(data);
1938 MMPLAYER_RETURN_IF_FAIL(player);
1939 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1941 switch (GST_MESSAGE_TYPE(msg)) {
1942 case GST_MESSAGE_UNKNOWN:
1943 LOGD("unknown message received");
1946 case GST_MESSAGE_EOS:
1947 LOGD("GST_MESSAGE_EOS received");
1948 __mmplayer_gst_handle_eos_message(player, msg);
1951 case GST_MESSAGE_ERROR:
1952 __mmplayer_gst_handle_error_message(player, msg);
1955 case GST_MESSAGE_WARNING:
1958 GError *error = NULL;
1960 gst_message_parse_warning(msg, &error, &debug);
1962 LOGD("warning : %s", error->message);
1963 LOGD("debug : %s", debug);
1965 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1967 MMPLAYER_FREEIF(debug);
1968 g_error_free(error);
1972 case GST_MESSAGE_TAG:
1974 LOGD("GST_MESSAGE_TAG");
1975 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1976 LOGW("failed to extract tags from gstmessage");
1980 case GST_MESSAGE_BUFFERING:
1981 __mmplayer_gst_handle_buffering_message(player, msg);
1984 case GST_MESSAGE_STATE_CHANGED:
1985 __mmplayer_gst_handle_state_message(player, msg);
1988 case GST_MESSAGE_CLOCK_LOST:
1990 GstClock *clock = NULL;
1991 gboolean need_new_clock = FALSE;
1993 gst_message_parse_clock_lost(msg, &clock);
1994 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1996 if (!player->videodec_linked)
1997 need_new_clock = TRUE;
1998 else if (!player->ini.use_system_clock)
1999 need_new_clock = TRUE;
2001 if (need_new_clock) {
2002 LOGD("Provide clock is TRUE, do pause->resume");
2003 __mmplayer_gst_pause(player, FALSE);
2004 __mmplayer_gst_resume(player, FALSE);
2009 case GST_MESSAGE_NEW_CLOCK:
2011 GstClock *clock = NULL;
2012 gst_message_parse_new_clock(msg, &clock);
2013 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2017 case GST_MESSAGE_ELEMENT:
2018 __mmplayer_gst_handle_element_message(player, msg);
2021 case GST_MESSAGE_DURATION_CHANGED:
2023 LOGD("GST_MESSAGE_DURATION_CHANGED");
2024 if (!__mmplayer_gst_handle_duration(player, msg))
2025 LOGW("failed to update duration");
2029 case GST_MESSAGE_ASYNC_START:
2030 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2033 case GST_MESSAGE_ASYNC_DONE:
2034 __mmplayer_gst_handle_async_done_message(player, msg);
2037 #if 0 /* delete unnecessary logs */
2038 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2039 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2040 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2041 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2042 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2043 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2044 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2045 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2046 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2047 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2048 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2049 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2050 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2051 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2052 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2059 /* should not call 'gst_message_unref(msg)' */
2063 static GstBusSyncReply
2064 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2066 mmplayer_t *player = (mmplayer_t *)data;
2067 GstBusSyncReply reply = GST_BUS_DROP;
2069 if (!(player->pipeline && player->pipeline->mainbin)) {
2070 LOGE("player pipeline handle is null");
2071 return GST_BUS_PASS;
2074 if (!__mmplayer_gst_check_useful_message(player, message)) {
2075 gst_message_unref(message);
2076 return GST_BUS_DROP;
2079 switch (GST_MESSAGE_TYPE(message)) {
2080 case GST_MESSAGE_TAG:
2081 __mmplayer_gst_extract_tag_from_msg(player, message);
2085 GstTagList *tags = NULL;
2087 gst_message_parse_tag(message, &tags);
2089 LOGE("TAGS received from element \"%s\".",
2090 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2092 gst_tag_list_foreach(tags, print_tag, NULL);
2093 gst_tag_list_unref(tags);
2101 case GST_MESSAGE_DURATION_CHANGED:
2102 __mmplayer_gst_handle_duration(player, message);
2104 case GST_MESSAGE_ASYNC_DONE:
2105 /* NOTE:Don't call gst_callback directly
2106 * because previous frame can be showed even though this message is received for seek.
2109 reply = GST_BUS_PASS;
2113 if (reply == GST_BUS_DROP)
2114 gst_message_unref(message);
2120 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2122 GstElement *appsrc = element;
2123 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2124 GstBuffer *buffer = NULL;
2125 GstFlowReturn ret = GST_FLOW_OK;
2128 MMPLAYER_RETURN_IF_FAIL(element);
2129 MMPLAYER_RETURN_IF_FAIL(buf);
2131 buffer = gst_buffer_new();
2133 if (buf->offset < 0 || buf->len < 0) {
2134 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2138 if (buf->offset >= buf->len) {
2139 LOGD("call eos appsrc");
2140 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2144 if (buf->len - buf->offset < size)
2145 len = buf->len - buf->offset;
2147 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2148 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2149 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2151 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2152 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2158 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2160 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2162 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2164 buf->offset = (int)size;
2170 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2172 mmplayer_t *player = (mmplayer_t *)user_data;
2173 mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2174 guint64 current_level_bytes = 0;
2176 MMPLAYER_RETURN_IF_FAIL(player);
2178 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2179 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2180 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2181 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2182 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2183 type = MM_PLAYER_STREAM_TYPE_TEXT;
2185 LOGE("can not enter here");
2189 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2191 LOGI("type: %d, level: %"G_GUINT64_FORMAT, type, current_level_bytes);
2193 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2194 if (player->media_stream_buffer_status_cb[type])
2195 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2196 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2200 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2202 mmplayer_t *player = (mmplayer_t *)user_data;
2203 mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2204 guint64 current_level_bytes = 0;
2206 MMPLAYER_RETURN_IF_FAIL(player);
2208 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2209 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2210 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2211 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2212 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2213 type = MM_PLAYER_STREAM_TYPE_TEXT;
2215 LOGE("can not enter here");
2219 LOGI("type: %d, buffer is full", type);
2221 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2223 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2225 if (player->media_stream_buffer_status_cb[type])
2226 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2228 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2232 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2234 mmplayer_t *player = (mmplayer_t *)user_data;
2235 mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2237 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2239 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2240 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2241 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2242 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2243 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2244 type = MM_PLAYER_STREAM_TYPE_TEXT;
2246 LOGE("can not enter here");
2250 LOGD("type: %d, pos: %"G_GUINT64_FORMAT, type, position);
2251 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2253 if (player->media_stream_seek_data_cb[type])
2254 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2255 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2261 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2263 #define MAX_LEN_NAME 20
2265 gboolean ret = FALSE;
2266 GstPad *sinkpad = NULL;
2267 gchar *prefix = NULL;
2268 gchar dec_name[MAX_LEN_NAME] = {0, };
2269 main_element_id_e elem_id = MMPLAYER_M_NUM;
2271 mmplayer_gst_element_t *mainbin = NULL;
2272 GstElement *decodebin = NULL;
2273 GstCaps *dec_caps = NULL;
2277 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2279 player->pipeline->mainbin, FALSE);
2280 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2282 mainbin = player->pipeline->mainbin;
2284 case MM_PLAYER_STREAM_TYPE_AUDIO:
2286 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2288 case MM_PLAYER_STREAM_TYPE_VIDEO:
2290 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2293 LOGE("invalid type %d", type);
2297 if (mainbin[elem_id].gst) {
2298 LOGE("elem(%d) is already created", elem_id);
2302 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2304 /* create decodebin */
2305 decodebin = gst_element_factory_make("decodebin", dec_name);
2307 LOGE("failed to create %s", dec_name);
2311 mainbin[elem_id].id = elem_id;
2312 mainbin[elem_id].gst = decodebin;
2314 /* raw pad handling signal */
2315 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2316 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2318 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2319 before looking for any elements that can handle that stream.*/
2320 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2321 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2323 /* This signal is emitted when a element is added to the bin.*/
2324 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2325 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2327 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2328 LOGE("failed to add new decodebin");
2332 dec_caps = gst_pad_query_caps(srcpad, NULL);
2334 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2335 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2336 gst_caps_unref(dec_caps);
2339 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2341 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2342 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2345 gst_object_unref(GST_OBJECT(sinkpad));
2347 gst_element_sync_state_with_parent(decodebin);
2353 gst_object_unref(GST_OBJECT(sinkpad));
2355 if (mainbin[elem_id].gst) {
2356 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2357 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2358 gst_object_unref(mainbin[elem_id].gst);
2359 mainbin[elem_id].gst = NULL;
2367 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2369 #define MAX_LEN_NAME 20
2370 mmplayer_gst_element_t *mainbin = NULL;
2371 gchar *prefix = NULL;
2372 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2374 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2375 GstElement *src = NULL, *queue = NULL;
2376 GstPad *srcpad = NULL;
2379 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2380 player->pipeline->mainbin, FALSE);
2382 mainbin = player->pipeline->mainbin;
2384 LOGD("type(%d) path is creating", type);
2386 case MM_PLAYER_STREAM_TYPE_AUDIO:
2388 if (mainbin[MMPLAYER_M_SRC].gst)
2389 src_id = MMPLAYER_M_2ND_SRC;
2391 src_id = MMPLAYER_M_SRC;
2392 queue_id = MMPLAYER_M_A_BUFFER;
2394 case MM_PLAYER_STREAM_TYPE_VIDEO:
2396 src_id = MMPLAYER_M_SRC;
2397 queue_id = MMPLAYER_M_V_BUFFER;
2399 case MM_PLAYER_STREAM_TYPE_TEXT:
2400 prefix = "subtitle";
2401 src_id = MMPLAYER_M_SUBSRC;
2402 queue_id = MMPLAYER_M_S_BUFFER;
2405 LOGE("invalid type %d", type);
2409 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2410 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2413 src = gst_element_factory_make("appsrc", src_name);
2415 LOGF("failed to create %s", src_name);
2419 mainbin[src_id].id = src_id;
2420 mainbin[src_id].gst = src;
2422 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2423 "caps", caps, NULL);
2425 /* size of many video frames are larger than default blocksize as 4096 */
2426 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2427 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2429 if (player->media_stream_buffer_max_size[type] > 0)
2430 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2432 if (player->media_stream_buffer_min_percent[type] > 0)
2433 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2435 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2436 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2438 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2439 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2440 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2441 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2442 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2443 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2446 queue = gst_element_factory_make("queue2", queue_name);
2448 LOGE("failed to create %s", queue_name);
2451 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2453 mainbin[queue_id].id = queue_id;
2454 mainbin[queue_id].gst = queue;
2456 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2457 LOGE("failed to add src");
2461 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2462 LOGE("failed to add queue");
2466 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2467 LOGE("failed to link src and queue");
2471 /* create decoder */
2472 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2474 LOGE("failed to get srcpad of queue");
2478 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2479 __mmplayer_gst_create_decoder(player, srcpad, caps);
2481 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2482 LOGE("failed to create decoder");
2483 gst_object_unref(GST_OBJECT(srcpad));
2487 gst_object_unref(GST_OBJECT(srcpad));
2491 if (mainbin[src_id].gst) {
2492 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2493 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2494 gst_object_unref(mainbin[src_id].gst);
2495 mainbin[src_id].gst = NULL;
2498 if (mainbin[queue_id].gst) {
2499 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2500 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2501 gst_object_unref(mainbin[queue_id].gst);
2502 mainbin[queue_id].gst = NULL;
2509 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2511 GstPad *sinkpad = NULL;
2512 GstCaps *caps = NULL;
2513 GstElement *new_element = NULL;
2514 GstStructure *str = NULL;
2515 const gchar *name = NULL;
2517 mmplayer_t *player = (mmplayer_t *)data;
2521 MMPLAYER_RETURN_IF_FAIL(element && pad);
2522 MMPLAYER_RETURN_IF_FAIL(player &&
2524 player->pipeline->mainbin);
2526 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2527 * num_dynamic_pad will decreased after creating a sinkbin.
2529 player->num_dynamic_pad++;
2530 LOGD("stream count inc : %d", player->num_dynamic_pad);
2532 caps = gst_pad_query_caps(pad, NULL);
2533 MMPLAYER_CHECK_NULL(caps);
2535 str = gst_caps_get_structure(caps, 0);
2536 name = gst_structure_get_string(str, "media");
2538 LOGE("cannot get mimetype from structure.");
2542 if (strstr(name, "video")) {
2544 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2546 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2547 if (player->v_stream_caps) {
2548 gst_caps_unref(player->v_stream_caps);
2549 player->v_stream_caps = NULL;
2552 new_element = gst_element_factory_make("fakesink", NULL);
2553 player->num_dynamic_pad--;
2558 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2559 LOGE("failed to autoplug for caps");
2563 gst_caps_unref(caps);
2568 /* excute new_element if created*/
2570 LOGD("adding new element to pipeline");
2572 /* set state to READY before add to bin */
2573 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2575 /* add new element to the pipeline */
2576 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2577 LOGE("failed to add autoplug element to bin");
2581 /* get pad from element */
2582 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2584 LOGE("failed to get sinkpad from autoplug element");
2589 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2590 LOGE("failed to link autoplug element");
2594 gst_object_unref(sinkpad);
2597 /* run. setting PLAYING here since streamming source is live source */
2598 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2602 gst_caps_unref(caps);
2608 STATE_CHANGE_FAILED:
2610 /* FIXIT : take care if new_element has already added to pipeline */
2612 gst_object_unref(GST_OBJECT(new_element));
2615 gst_object_unref(GST_OBJECT(sinkpad));
2618 gst_caps_unref(caps);
2620 /* FIXIT : how to inform this error to MSL ????? */
2621 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2622 * then post an error to application
2627 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2629 mmplayer_t *player = (mmplayer_t *)data;
2633 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2634 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2635 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2636 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2638 * [1] audio and video will be dumped with filesink.
2639 * [2] autoplugging is done by just using pad caps.
2640 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2641 * and the video will be dumped via filesink.
2643 if (player->num_dynamic_pad == 0) {
2644 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2646 if (!__mmplayer_gst_remove_fakesink(player,
2647 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2648 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2649 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2650 * source element are not same. To overcome this situation, this function will called
2651 * several places and several times. Therefore, this is not an error case.
2656 /* create dot before error-return. for debugging */
2657 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2659 player->no_more_pad = TRUE;
2665 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2667 GstElement *element = NULL;
2668 gchar *user_agent = NULL;
2669 MMHandleType attrs = 0;
2672 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2674 /* get profile attribute */
2675 attrs = MMPLAYER_GET_ATTRS(player);
2677 LOGE("failed to get content attribute");
2681 element = gst_element_factory_make("rtspsrc", "rtsp source");
2683 LOGE("failed to create rtspsrc element");
2688 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2690 SECURE_LOGD("user_agent : %s", user_agent);
2692 /* setting property to streaming source */
2693 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2695 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2697 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2698 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2699 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2700 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2707 __mmplayer_gst_make_http_src(mmplayer_t *player)
2709 GstElement *element = NULL;
2710 MMHandleType attrs = 0;
2711 gchar *user_agent, *cookies, **cookie_list;
2712 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2713 user_agent = cookies = NULL;
2717 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2719 /* get profile attribute */
2720 attrs = MMPLAYER_GET_ATTRS(player);
2722 LOGE("failed to get content attribute");
2726 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2728 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2730 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2735 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2736 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2738 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2739 http_timeout = player->ini.http_timeout;
2742 SECURE_LOGD("location : %s", player->profile.uri);
2743 SECURE_LOGD("cookies : %s", cookies);
2744 SECURE_LOGD("user_agent : %s", user_agent);
2745 LOGD("timeout : %d", http_timeout);
2747 /* setting property to streaming source */
2748 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2749 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), NULL);
2751 /* parsing cookies */
2752 if ((cookie_list = util_get_cookie_list((const char *)cookies))) {
2753 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2754 g_strfreev(cookie_list);
2758 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2760 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2761 LOGW("[DASH] this is still experimental feature");
2768 __mmplayer_gst_make_file_src(mmplayer_t *player)
2770 GstElement *element = NULL;
2773 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2775 LOGD("using filesrc for 'file://' handler");
2776 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2777 LOGE("failed to get storage info");
2781 element = gst_element_factory_make("filesrc", "source");
2783 LOGE("failed to create filesrc");
2787 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2794 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2796 mmplayer_t *player = (mmplayer_t *)data;
2798 g_return_val_if_fail(player, FALSE);
2799 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2801 gst_message_ref(msg);
2803 g_mutex_lock(&player->bus_msg_q_lock);
2804 g_queue_push_tail(player->bus_msg_q, msg);
2805 g_mutex_unlock(&player->bus_msg_q_lock);
2807 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2808 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2809 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2813 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2815 mmplayer_t *player = (mmplayer_t *)(data);
2816 GstMessage *msg = NULL;
2820 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2822 player->pipeline->mainbin &&
2823 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2826 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2828 LOGE("cannot get BUS from the pipeline");
2832 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2834 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2835 while (!player->bus_msg_thread_exit) {
2836 g_mutex_lock(&player->bus_msg_q_lock);
2837 msg = g_queue_pop_head(player->bus_msg_q);
2838 g_mutex_unlock(&player->bus_msg_q_lock);
2840 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2843 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2844 /* handle the gst msg */
2845 __mmplayer_gst_bus_msg_callback(msg, player);
2846 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2847 gst_message_unref(msg);
2850 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2851 gst_object_unref(GST_OBJECT(bus));
2858 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
2860 gint64 dur_nsec = 0;
2863 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2865 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2866 return MM_ERROR_NONE;
2868 /* NOTE : duration cannot be zero except live streaming.
2869 * Since some element could have some timing problemn with quering duration, try again.
2871 if (player->duration == 0) {
2872 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2873 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2874 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2875 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2876 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2877 player->pending_seek.is_pending = true;
2878 player->pending_seek.pos = position;
2879 player->seek_state = MMPLAYER_SEEK_NONE;
2880 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2881 return MM_ERROR_PLAYER_NO_OP;
2883 player->seek_state = MMPLAYER_SEEK_NONE;
2884 return MM_ERROR_PLAYER_SEEK;
2887 player->duration = dur_nsec;
2890 if (player->duration > 0 && player->duration < position) {
2891 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2892 return MM_ERROR_INVALID_ARGUMENT;
2896 return MM_ERROR_NONE;
2900 __mmplayer_gst_check_seekable(mmplayer_t *player)
2902 GstQuery *query = NULL;
2903 gboolean seekable = FALSE;
2905 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2909 query = gst_query_new_seeking(GST_FORMAT_TIME);
2910 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2911 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2912 gst_query_unref(query);
2915 LOGW("non-seekable content");
2916 player->seek_state = MMPLAYER_SEEK_NONE;
2920 LOGW("failed to get seeking query");
2921 gst_query_unref(query); /* keep seeking operation */
2928 __mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
2930 GstState element_state = GST_STATE_VOID_PENDING;
2931 GstState element_pending_state = GST_STATE_VOID_PENDING;
2932 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2937 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2939 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2942 ret = gst_element_set_state(element, state);
2943 if (ret == GST_STATE_CHANGE_FAILURE) {
2944 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2946 /* dump state of all element */
2947 __mmplayer_dump_pipeline_state(player);
2949 return MM_ERROR_PLAYER_INTERNAL;
2952 /* return here so state transition to be done in async mode */
2954 LOGD("async state transition. not waiting for state complete.");
2955 return MM_ERROR_NONE;
2958 /* wait for state transition */
2959 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2960 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2961 LOGE("failed to change [%s] element state to [%s] within %d sec",
2962 GST_ELEMENT_NAME(element),
2963 gst_element_state_get_name(state), timeout);
2965 LOGE(" [%s] state : %s pending : %s",
2966 GST_ELEMENT_NAME(element),
2967 gst_element_state_get_name(element_state),
2968 gst_element_state_get_name(element_pending_state));
2970 /* dump state of all element */
2971 __mmplayer_dump_pipeline_state(player);
2973 return MM_ERROR_PLAYER_INTERNAL;
2976 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2980 return MM_ERROR_NONE;
2984 __mmplayer_gst_start(mmplayer_t *player)
2986 int ret = MM_ERROR_NONE;
2987 gboolean async = FALSE;
2991 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2993 /* NOTE : if SetPosition was called before Start. do it now
2994 * streaming doesn't support it. so it should be always sync
2995 * !!create one more api to check if there is pending seek rather than checking variables
2997 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2998 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2999 ret = __mmplayer_gst_pause(player, FALSE);
3000 if (ret != MM_ERROR_NONE) {
3001 LOGE("failed to set state to PAUSED for pending seek");
3005 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3006 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3007 LOGW("failed to seek pending postion. starting from the begin of content");
3010 LOGD("current state before doing transition");
3011 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3012 MMPLAYER_PRINT_STATE(player);
3014 /* set pipeline state to PLAYING */
3015 ret = __mmplayer_gst_set_state(player,
3016 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3017 if (ret != MM_ERROR_NONE) {
3018 LOGE("failed to set state to PLAYING");
3022 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3024 /* generating debug info before returning error */
3025 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3033 __mmplayer_gst_stop(mmplayer_t *player)
3035 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3036 MMHandleType attrs = 0;
3037 gboolean rewind = FALSE;
3039 int ret = MM_ERROR_NONE;
3043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3044 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3046 LOGD("current state before doing transition");
3047 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3048 MMPLAYER_PRINT_STATE(player);
3050 attrs = MMPLAYER_GET_ATTRS(player);
3052 LOGE("cannot get content attribute");
3053 return MM_ERROR_PLAYER_INTERNAL;
3056 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3057 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3059 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3060 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3063 if (player->es_player_push_mode)
3064 /* disable the async state transition because there could be no data in the pipeline */
3065 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3068 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3070 if (player->es_player_push_mode) {
3071 /* enable the async state transition as default operation */
3072 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3075 /* return if set_state has failed */
3076 if (ret != MM_ERROR_NONE) {
3077 LOGE("failed to set state.");
3083 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3084 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3085 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3086 LOGW("failed to rewind");
3087 ret = MM_ERROR_PLAYER_SEEK;
3092 player->sent_bos = FALSE;
3094 if (player->es_player_push_mode) //for cloudgame
3097 /* wait for seek to complete */
3098 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3099 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3100 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3102 LOGE("fail to stop player.");
3103 ret = MM_ERROR_PLAYER_INTERNAL;
3104 __mmplayer_dump_pipeline_state(player);
3107 /* generate dot file if enabled */
3108 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3116 __mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3118 int ret = MM_ERROR_NONE;
3122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3123 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3125 LOGD("current state before doing transition");
3126 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3127 MMPLAYER_PRINT_STATE(player);
3129 /* set pipeline status to PAUSED */
3130 ret = __mmplayer_gst_set_state(player,
3131 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3136 if (ret != MM_ERROR_NONE) {
3137 GstMessage *msg = NULL;
3138 GTimer *timer = NULL;
3139 gdouble MAX_TIMEOUT_SEC = 3;
3141 LOGE("failed to set state to PAUSED");
3143 if (!player->bus_watcher) {
3144 LOGE("there is no bus msg thread. pipeline is shutting down.");
3148 if (player->msg_posted) {
3149 LOGE("error msg is already posted.");
3153 timer = g_timer_new();
3154 g_timer_start(timer);
3156 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3159 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3161 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3162 GError *error = NULL;
3164 /* parse error code */
3165 gst_message_parse_error(msg, &error, NULL);
3167 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3168 /* Note : the streaming error from the streaming source is handled
3169 * using __mmplayer_handle_streaming_error.
3171 __mmplayer_handle_streaming_error(player, msg);
3174 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3176 if (error->domain == GST_STREAM_ERROR)
3177 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3178 else if (error->domain == GST_RESOURCE_ERROR)
3179 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3180 else if (error->domain == GST_LIBRARY_ERROR)
3181 ret = __mmplayer_gst_handle_library_error(player, error->code);
3182 else if (error->domain == GST_CORE_ERROR)
3183 ret = __mmplayer_gst_handle_core_error(player, error->code);
3185 g_error_free(error);
3187 player->msg_posted = TRUE;
3189 gst_message_unref(msg);
3191 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3193 gst_object_unref(bus);
3194 g_timer_stop(timer);
3195 g_timer_destroy(timer);
3200 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3201 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3202 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3204 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3207 /* generate dot file before returning error */
3208 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3216 __mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3218 int ret = MM_ERROR_NONE;
3223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3224 MM_ERROR_PLAYER_NOT_INITIALIZED);
3226 LOGD("current state before doing transition");
3227 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3228 MMPLAYER_PRINT_STATE(player);
3231 LOGD("do async state transition to PLAYING");
3233 /* set pipeline state to PLAYING */
3234 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3236 ret = __mmplayer_gst_set_state(player,
3237 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3238 if (ret != MM_ERROR_NONE) {
3239 LOGE("failed to set state to PLAYING");
3244 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3247 /* generate dot file */
3248 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3255 /* sending event to one of sinkelements */
3257 __mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3259 GstEvent *event2 = NULL;
3260 GList *sinks = NULL;
3261 gboolean res = FALSE;
3264 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3265 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3267 /* While adding subtitles in live feeds seek is getting called.
3268 Adding defensive check in framework layer.*/
3269 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3270 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3271 LOGE("Should not send seek event during live playback");
3276 if (player->play_subtitle)
3277 event2 = gst_event_copy((const GstEvent *)event);
3279 sinks = player->sink_elements;
3281 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3283 if (GST_IS_ELEMENT(sink)) {
3284 /* keep ref to the event */
3285 gst_event_ref(event);
3287 if ((res = gst_element_send_event(sink, event))) {
3288 LOGD("sending event[%s] to sink element [%s] success!",
3289 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3291 /* rtsp case, asyn_done is not called after seek during pause state */
3292 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3293 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3294 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3295 LOGD("RTSP seek completed, after pause state..");
3296 player->seek_state = MMPLAYER_SEEK_NONE;
3297 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3303 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3304 sinks = g_list_next(sinks);
3311 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3312 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3315 sinks = g_list_next(sinks);
3318 /* Note : Textbin is not linked to the video or audio bin.
3319 * It needs to send the event to the text sink seperatelly.
3321 if (player->play_subtitle && player->pipeline) {
3322 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3324 if (GST_IS_ELEMENT(text_sink)) {
3325 /* keep ref to the event */
3326 gst_event_ref(event2);
3328 if ((res = gst_element_send_event(text_sink, event2)))
3329 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3330 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3332 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3333 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3335 gst_event_unref(event2);
3339 gst_event_unref(event);
3347 __mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3348 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3349 gint64 cur, GstSeekType stop_type, gint64 stop)
3351 GstEvent *event = NULL;
3352 gboolean result = FALSE;
3356 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3358 if (player->pipeline && player->pipeline->textbin)
3359 __mmplayer_drop_subtitle(player, FALSE);
3361 event = gst_event_new_seek(rate, format, flags, cur_type,
3362 cur, stop_type, stop);
3364 result = __mmplayer_gst_send_event_to_sink(player, event);
3372 __mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3374 int ret = MM_ERROR_NONE;
3375 gint64 pos_nsec = 0;
3376 gboolean accurated = FALSE;
3377 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3380 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3381 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3383 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3384 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3387 ret = __mmplayer_gst_check_duration(player, position);
3388 if (ret != MM_ERROR_NONE) {
3389 LOGE("failed to check duration 0x%X", ret);
3390 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3393 if (!__mmplayer_gst_check_seekable(player))
3394 return MM_ERROR_PLAYER_NO_OP;
3396 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3397 position, player->playback_rate, player->duration);
3399 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3400 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3401 This causes problem is position calculation during normal pause resume scenarios also.
3402 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3403 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3404 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3405 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3406 LOGW("getting current position failed in seek");
3408 player->last_position = pos_nsec;
3409 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3412 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3413 LOGD("not completed seek");
3414 return MM_ERROR_PLAYER_DOING_SEEK;
3417 if (!internal_called)
3418 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3420 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3421 that's why set position through property. */
3422 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3423 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3424 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3425 (!player->videodec_linked) && (!player->audiodec_linked)) {
3427 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3428 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3430 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3431 player->seek_state = MMPLAYER_SEEK_NONE;
3432 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3434 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3436 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3438 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3440 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3441 GST_FORMAT_TIME, seek_flags,
3442 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3443 LOGE("failed to set position");
3448 /* NOTE : store last seeking point to overcome some bad operation
3449 * (returning zero when getting current position) of some elements
3451 player->last_position = position;
3453 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3454 if (player->playback_rate > 1.0)
3455 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3457 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3458 LOGD("buffering should be reset after seeking");
3459 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3460 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3464 return MM_ERROR_NONE;
3467 player->pending_seek.is_pending = true;
3468 player->pending_seek.pos = position;
3470 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3471 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3472 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3473 player->pending_seek.pos);
3475 return MM_ERROR_NONE;
3478 player->seek_state = MMPLAYER_SEEK_NONE;
3479 return MM_ERROR_PLAYER_SEEK;
3483 __mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3485 #define TRICKPLAY_OFFSET GST_MSECOND
3487 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3488 gint64 pos_nsec = 0;
3489 gboolean ret = TRUE;
3491 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3492 MM_ERROR_PLAYER_NOT_INITIALIZED);
3494 current_state = MMPLAYER_CURRENT_STATE(player);
3496 /* NOTE : query position except paused state to overcome some bad operation
3497 * please refer to below comments in details
3499 if (current_state != MM_PLAYER_STATE_PAUSED)
3500 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3502 /* NOTE : get last point to overcome some bad operation of some elements
3503 *(returning zero when getting current position in paused state
3504 * and when failed to get postion during seeking
3506 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3507 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3509 if (player->playback_rate < 0.0)
3510 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3512 pos_nsec = player->last_position;
3515 pos_nsec = player->last_position;
3517 player->last_position = pos_nsec;
3519 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3522 if (player->duration > 0 && pos_nsec > player->duration)
3523 pos_nsec = player->duration;
3525 player->last_position = pos_nsec;
3528 *position = pos_nsec;
3530 return MM_ERROR_NONE;
3534 __mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3536 #define STREAMING_IS_FINISHED 0
3537 #define BUFFERING_MAX_PER 100
3538 #define DEFAULT_PER_VALUE -1
3539 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3541 mmplayer_gst_element_t *mainbin = NULL;
3542 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3543 gint64 buffered_total = 0;
3544 gint64 position = 0;
3545 gint buffered_sec = -1;
3546 GstBufferingMode mode = GST_BUFFERING_STREAM;
3547 gint64 content_size_time = player->duration;
3548 guint64 content_size_bytes = player->http_content_size;
3550 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3552 player->pipeline->mainbin,
3553 MM_ERROR_PLAYER_NOT_INITIALIZED);
3555 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3560 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3561 /* and rtsp is not ready yet. */
3562 LOGW("it's only used for http streaming case");
3563 return MM_ERROR_PLAYER_NO_OP;
3566 if (content_size_time <= 0 || content_size_bytes <= 0) {
3567 LOGW("there is no content size");
3568 return MM_ERROR_NONE;
3571 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3572 LOGW("fail to get current position");
3573 return MM_ERROR_NONE;
3576 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3577 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3579 mainbin = player->pipeline->mainbin;
3580 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3582 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3583 GstQuery *query = NULL;
3584 gint byte_in_rate = 0, byte_out_rate = 0;
3585 gint64 estimated_total = 0;
3587 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3588 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3589 LOGW("fail to get buffering query from queue2");
3591 gst_query_unref(query);
3592 return MM_ERROR_NONE;
3595 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3596 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3598 if (mode == GST_BUFFERING_STREAM) {
3599 /* using only queue in case of push mode(ts / mp3) */
3600 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3601 GST_FORMAT_BYTES, &buffered_total)) {
3602 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3603 end_per = 100 * buffered_total / content_size_bytes;
3606 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3608 guint num_of_ranges = 0;
3609 gint64 start_byte = 0, stop_byte = 0;
3611 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3612 if (estimated_total != STREAMING_IS_FINISHED) {
3613 /* buffered size info from queue2 */
3614 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3615 for (idx = 0; idx < num_of_ranges; idx++) {
3616 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3617 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3619 buffered_total += (stop_byte - start_byte);
3622 end_per = BUFFERING_MAX_PER;
3625 gst_query_unref(query);
3628 if (end_per == DEFAULT_PER_VALUE) {
3629 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3631 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3633 /* buffered size info from multiqueue */
3634 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3635 guint curr_size_bytes = 0;
3636 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3637 "curr-size-bytes", &curr_size_bytes, NULL);
3638 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3639 buffered_total += curr_size_bytes;
3642 if (avg_byterate > 0)
3643 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3644 else if (player->total_maximum_bitrate > 0)
3645 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3646 else if (player->total_bitrate > 0)
3647 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3649 if (buffered_sec >= 0)
3650 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3654 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3655 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3657 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3658 buffered_total, buffered_sec, *start_pos, *end_pos);
3660 return MM_ERROR_NONE;
3664 __mmplayer_gst_create_source(mmplayer_t *player)
3666 GstElement *element = NULL;
3669 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3670 player->pipeline->mainbin, NULL);
3672 /* setup source for gapless play */
3673 switch (player->profile.uri_type) {
3675 case MM_PLAYER_URI_TYPE_FILE:
3676 element = __mmplayer_gst_make_file_src(player);
3678 case MM_PLAYER_URI_TYPE_URL_HTTP:
3679 element = __mmplayer_gst_make_http_src(player);
3682 LOGE("not support uri type %d", player->profile.uri_type);
3687 LOGE("failed to create source element");
3696 __mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3698 MMHandleType attrs = 0;
3701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3702 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3704 /* get profile attribute */
3705 attrs = MMPLAYER_GET_ATTRS(player);
3707 LOGE("failed to get content attribute");
3708 return MM_ERROR_PLAYER_INTERNAL;
3711 SECURE_LOGD("uri : %s", player->profile.uri);
3713 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3714 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3715 LOGE("failed to commit");
3717 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3718 return MM_ERROR_PLAYER_INTERNAL;
3720 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3721 return MM_ERROR_PLAYER_INTERNAL;
3723 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3724 return MM_ERROR_PLAYER_INTERNAL;
3727 return MM_ERROR_NONE;
3731 __mmplayer_gst_build_pipeline(mmplayer_t *player)
3733 mmplayer_gst_element_t *mainbin = NULL;
3734 GstElement *src_elem = NULL;
3735 GstElement *autoplug_elem = NULL;
3736 GList *element_bucket = NULL;
3737 MMHandleType attrs = 0;
3738 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3741 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3742 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3744 /* get profile attribute */
3745 attrs = MMPLAYER_GET_ATTRS(player);
3747 LOGE("failed to get content attribute");
3748 return MM_ERROR_PLAYER_INTERNAL;
3751 LOGD("uri type %d", player->profile.uri_type);
3753 /* create source element */
3754 switch (player->profile.uri_type) {
3755 case MM_PLAYER_URI_TYPE_URL_RTSP:
3756 src_elem = __mmplayer_gst_make_rtsp_src(player);
3758 case MM_PLAYER_URI_TYPE_URL_HTTP:
3759 src_elem = __mmplayer_gst_make_http_src(player);
3761 case MM_PLAYER_URI_TYPE_FILE:
3762 src_elem = __mmplayer_gst_make_file_src(player);
3764 case MM_PLAYER_URI_TYPE_SS:
3766 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3767 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3769 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3773 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3774 LOGD("get timeout from ini");
3775 http_timeout = player->ini.http_timeout;
3778 /* setting property to streaming source */
3779 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3782 case MM_PLAYER_URI_TYPE_MEM:
3784 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3786 src_elem = gst_element_factory_make("appsrc", "mem-source");
3788 LOGE("failed to create appsrc element");
3792 g_object_set(src_elem, "stream-type", stream_type,
3793 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3795 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3796 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3797 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3798 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3802 LOGE("not support uri type");
3807 LOGE("failed to create source element");
3808 return MM_ERROR_PLAYER_INTERNAL;
3811 mainbin = player->pipeline->mainbin;
3813 /* take source element */
3814 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3816 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3817 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3818 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3820 /* create next element for auto-plugging */
3821 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3822 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3823 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3824 if (!autoplug_elem) {
3825 LOGE("failed to create typefind element");
3829 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3830 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3831 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3832 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3833 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3834 if (!autoplug_elem) {
3835 LOGE("failed to create decodebin");
3839 /* default size of mq in decodebin is 2M
3840 * but it can cause blocking issue during seeking depends on content. */
3841 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3844 if (autoplug_elem) {
3845 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3846 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3847 mainbin[autoplug_elem_id].gst = autoplug_elem;
3849 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3852 /* add elements to pipeline */
3853 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3854 LOGE("failed to add elements to pipeline");
3858 /* linking elements in the bucket by added order. */
3859 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3860 LOGE("failed to link some elements");
3864 /* FIXME: need to check whether this is required or not. */
3865 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3866 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3867 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3868 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3870 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3871 LOGE("failed to create fakesink");
3874 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3876 /* take ownership of fakesink. we are reusing it */
3877 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3879 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3880 LOGE("failed to add fakesink to bin");
3881 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3886 g_list_free(element_bucket);
3889 return MM_ERROR_NONE;
3892 g_list_free(element_bucket);
3894 if (mainbin[MMPLAYER_M_SRC].gst)
3895 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3897 if (mainbin[autoplug_elem_id].gst)
3898 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3900 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3901 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3903 mainbin[MMPLAYER_M_SRC].gst = NULL;
3904 mainbin[autoplug_elem_id].gst = NULL;
3905 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3907 return MM_ERROR_PLAYER_INTERNAL;
3911 __mmplayer_gst_add_bus_watch(mmplayer_t *player)
3914 mmplayer_gst_element_t *mainbin = NULL;
3917 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3918 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3920 mainbin = player->pipeline->mainbin;
3922 /* connect bus callback */
3923 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3925 LOGE("cannot get bus from pipeline");
3926 return MM_ERROR_PLAYER_INTERNAL;
3929 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3930 player->context.thread_default = g_main_context_get_thread_default();
3931 if (player->context.thread_default == NULL) {
3932 player->context.thread_default = g_main_context_default();
3933 LOGD("thread-default context is the global default context");
3935 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3937 /* set sync handler to get tag synchronously */
3938 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3939 gst_object_unref(GST_OBJECT(bus));
3941 /* create gst bus_msb_cb thread */
3942 g_mutex_init(&player->bus_msg_thread_mutex);
3943 g_cond_init(&player->bus_msg_thread_cond);
3944 player->bus_msg_thread_exit = FALSE;
3945 player->bus_msg_thread =
3946 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3947 if (!player->bus_msg_thread) {
3948 LOGE("failed to create gst BUS msg thread");
3949 g_mutex_clear(&player->bus_msg_thread_mutex);
3950 g_cond_clear(&player->bus_msg_thread_cond);
3951 return MM_ERROR_PLAYER_INTERNAL;
3955 return MM_ERROR_NONE;