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 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
91 count = gst_tag_list_get_tag_size(list, tag);
93 LOGD("count = %d", count);
95 for (i = 0; i < count; i++) {
98 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
99 if (!gst_tag_list_get_string_index(list, tag, i, &str))
100 g_assert_not_reached();
102 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
106 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
108 g_print(" : %s", str);
116 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
118 /* check whether the error is posted from not-activated track or not */
120 gint active_pad_index = 0;
122 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
124 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
125 LOGD("current active pad index -%d", active_pad_index);
127 if (src_element_name) {
130 if (player->audio_decoders) {
131 GList *adec = player->audio_decoders;
132 for (; adec ; adec = g_list_next(adec)) {
133 gchar *name = adec->data;
135 LOGD("found audio decoder name = %s", name);
136 if (g_strrstr(name, src_element_name)) {
143 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
146 if (active_pad_index != msg_src_pos) {
147 LOGD("skip error because error is posted from no activated track");
155 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
157 /* Demuxer can't parse one track because it's corrupted.
158 * So, the decoder for it is not linked.
159 * But, it has one playable track.
161 if (g_strrstr(klass, "Demux")) {
162 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
167 if (player->pipeline->audiobin) { // PCM
168 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
170 LOGD("not found any available codec. Player should be destroyed.");
171 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
176 return MM_ERROR_PLAYER_INVALID_STREAM;
180 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
182 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
183 LOGE("Not supported subtitle.");
184 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
186 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
190 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
192 /* Decoder Custom Message */
193 if (!strstr(error->message, "ongoing"))
194 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
196 if (strncasecmp(klass, "audio", 5)) {
197 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
198 LOGD("Video can keep playing.");
199 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
201 } else if (strncasecmp(klass, "video", 5)) {
202 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
203 LOGD("Audio can keep playing.");
204 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
208 LOGD("not found any available codec. Player should be destroyed.");
209 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
213 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
215 if (strstr(error->message, "rights expired"))
216 return MM_ERROR_PLAYER_DRM_EXPIRED;
217 else if (strstr(error->message, "no rights"))
218 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219 else if (strstr(error->message, "has future rights"))
220 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221 else if (strstr(error->message, "opl violation"))
222 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
224 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
227 /* NOTE : decide gstreamer state whether there is some playable track or not. */
229 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
231 gchar *src_element_name = NULL;
232 GstElement *src_element = NULL;
233 GstElementFactory *factory = NULL;
234 const gchar *klass = NULL;
238 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
239 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
240 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
241 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
243 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
245 src_element = GST_ELEMENT_CAST(message->src);
247 return MM_ERROR_PLAYER_INTERNAL;
249 src_element_name = GST_ELEMENT_NAME(src_element);
250 if (!src_element_name)
251 return MM_ERROR_PLAYER_INTERNAL;
253 factory = gst_element_get_factory(src_element);
255 return MM_ERROR_PLAYER_INTERNAL;
257 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
259 return MM_ERROR_PLAYER_INTERNAL;
261 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
262 error->code, error->message, src_element_name, klass);
264 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
265 return MM_ERROR_NONE;
267 switch (error->code) {
268 case GST_STREAM_ERROR_DECODE:
269 return __mmplayer_gst_transform_error_decode(player, klass);
270 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
271 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
272 case GST_STREAM_ERROR_WRONG_TYPE:
273 return __mmplayer_gst_transform_error_type(player, src_element);
274 case GST_STREAM_ERROR_FAILED:
275 return __mmplayer_gst_transform_error_failed(player, klass, error);
276 case GST_STREAM_ERROR_DECRYPT:
277 case GST_STREAM_ERROR_DECRYPT_NOKEY:
278 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
279 return __mmplayer_gst_transform_error_decrypt(player, error);
286 return MM_ERROR_PLAYER_INVALID_STREAM;
290 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
292 gint trans_err = MM_ERROR_NONE;
296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
299 case GST_CORE_ERROR_MISSING_PLUGIN:
300 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
301 case GST_CORE_ERROR_STATE_CHANGE:
302 case GST_CORE_ERROR_SEEK:
303 case GST_CORE_ERROR_NOT_IMPLEMENTED:
304 case GST_CORE_ERROR_FAILED:
305 case GST_CORE_ERROR_TOO_LAZY:
306 case GST_CORE_ERROR_PAD:
307 case GST_CORE_ERROR_THREAD:
308 case GST_CORE_ERROR_NEGOTIATION:
309 case GST_CORE_ERROR_EVENT:
310 case GST_CORE_ERROR_CAPS:
311 case GST_CORE_ERROR_TAG:
312 case GST_CORE_ERROR_CLOCK:
313 case GST_CORE_ERROR_DISABLED:
315 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
325 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
327 gint trans_err = MM_ERROR_NONE;
331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
334 case GST_LIBRARY_ERROR_FAILED:
335 case GST_LIBRARY_ERROR_TOO_LAZY:
336 case GST_LIBRARY_ERROR_INIT:
337 case GST_LIBRARY_ERROR_SHUTDOWN:
338 case GST_LIBRARY_ERROR_SETTINGS:
339 case GST_LIBRARY_ERROR_ENCODE:
341 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
351 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
353 gint trans_err = MM_ERROR_NONE;
357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
360 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
361 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
363 case GST_RESOURCE_ERROR_NOT_FOUND:
364 case GST_RESOURCE_ERROR_OPEN_READ:
365 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
366 || MMPLAYER_IS_RTSP_STREAMING(player)) {
367 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
370 case GST_RESOURCE_ERROR_READ:
371 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
372 || MMPLAYER_IS_RTSP_STREAMING(player)) {
373 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
375 } else if (message != NULL && message->src != NULL) {
376 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
377 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
379 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
380 path_type = MMPLAYER_PATH_VOD;
381 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
382 path_type = MMPLAYER_PATH_TEXT;
384 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
385 /* check storage state */
386 storage_get_state(player->storage_info[path_type].id, &storage_state);
387 player->storage_info[path_type].state = storage_state;
388 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
391 case GST_RESOURCE_ERROR_WRITE:
392 case GST_RESOURCE_ERROR_FAILED:
393 case GST_RESOURCE_ERROR_SEEK:
394 case GST_RESOURCE_ERROR_TOO_LAZY:
395 case GST_RESOURCE_ERROR_BUSY:
396 case GST_RESOURCE_ERROR_OPEN_WRITE:
397 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
398 case GST_RESOURCE_ERROR_CLOSE:
399 case GST_RESOURCE_ERROR_SYNC:
400 case GST_RESOURCE_ERROR_SETTINGS:
402 trans_err = MM_ERROR_PLAYER_INTERNAL;
412 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
414 gint trans_err = MM_ERROR_NONE;
418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
419 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
420 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
422 switch (error->code) {
423 case GST_STREAM_ERROR_FAILED:
424 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
425 case GST_STREAM_ERROR_DECODE:
426 case GST_STREAM_ERROR_WRONG_TYPE:
427 case GST_STREAM_ERROR_DECRYPT:
428 case GST_STREAM_ERROR_DECRYPT_NOKEY:
429 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
430 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
433 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
434 case GST_STREAM_ERROR_TOO_LAZY:
435 case GST_STREAM_ERROR_ENCODE:
436 case GST_STREAM_ERROR_DEMUX:
437 case GST_STREAM_ERROR_MUX:
438 case GST_STREAM_ERROR_FORMAT:
440 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
450 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
452 MMMessageParamType msg_param;
453 gchar *msg_src_element;
457 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
458 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
460 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
462 memset(&msg_param, 0, sizeof(MMMessageParamType));
464 if (error->domain == GST_CORE_ERROR) {
465 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
466 } else if (error->domain == GST_LIBRARY_ERROR) {
467 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
468 } else if (error->domain == GST_RESOURCE_ERROR) {
469 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
470 } else if (error->domain == GST_STREAM_ERROR) {
471 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
473 LOGW("This error domain is not defined.");
475 /* we treat system error as an internal error */
476 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
480 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
482 msg_param.data = (void *)error->message;
484 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
485 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
489 if (msg_param.code == MM_ERROR_NONE)
492 /* skip error to avoid duplicated posting */
493 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
494 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
495 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
496 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
498 /* The error will be handled by mused.
499 * @ref _mmplayer_manage_external_storage_state() */
501 LOGW("storage is removed, skip error post");
505 /* post error to application */
506 if (!player->msg_posted) {
507 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
508 /* don't post more if one was sent already */
509 player->msg_posted = TRUE;
511 LOGD("skip error post because it's sent already.");
520 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
523 MMMessageParamType msg_param;
524 gchar *msg_src_element = NULL;
525 GstStructure *s = NULL;
527 gchar *error_string = NULL;
531 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
532 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
534 s = gst_structure_copy(gst_message_get_structure(message));
537 if (!gst_structure_get_uint(s, "error_id", &error_id))
538 error_id = MMPLAYER_STREAMING_ERROR_NONE;
541 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
542 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
544 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
545 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
547 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
548 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
550 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
551 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
553 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
554 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
556 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
557 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
559 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
560 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
562 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
563 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
565 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
566 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
568 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
569 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
571 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
572 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
574 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
575 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
577 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
578 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
580 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
581 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
583 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
584 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
586 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
587 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
589 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
590 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
592 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
593 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
595 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
596 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
598 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
599 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
601 case MMPLAYER_STREAMING_ERROR_GONE:
602 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
604 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
605 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
607 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
608 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
610 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
611 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
613 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
614 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
616 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
617 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
619 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
620 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
622 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
623 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
625 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
626 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
628 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
629 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
631 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
632 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
634 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
635 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
637 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
638 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
640 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
641 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
643 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
644 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
646 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
647 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
649 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
650 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
652 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
653 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
655 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
656 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
658 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
659 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
661 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
662 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
664 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
665 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
667 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
668 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
670 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
671 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
673 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
674 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
678 gst_structure_free(s);
679 return MM_ERROR_PLAYER_STREAMING_FAIL;
683 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
685 msg_param.data = (void *)error_string;
688 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
690 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
691 msg_src_element, msg_param.code, (char *)msg_param.data);
694 /* post error to application */
695 if (!player->msg_posted) {
696 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
698 /* don't post more if one was sent already */
699 player->msg_posted = TRUE;
701 LOGD("skip error post because it's sent already.");
704 gst_structure_free(s);
705 MMPLAYER_FREEIF(error_string);
713 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
715 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
716 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
717 gst_tag_list_get_string(tags, "stitching_software",
718 &metadata->stitching_software);
719 gst_tag_list_get_string(tags, "projection_type",
720 &metadata->projection_type_string);
721 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
722 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
723 gst_tag_list_get_int(tags, "init_view_heading",
724 &metadata->init_view_heading);
725 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
726 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
727 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
728 gst_tag_list_get_int(tags, "full_pano_width_pixels",
729 &metadata->full_pano_width_pixels);
730 gst_tag_list_get_int(tags, "full_pano_height_pixels",
731 &metadata->full_pano_height_pixels);
732 gst_tag_list_get_int(tags, "cropped_area_image_width",
733 &metadata->cropped_area_image_width);
734 gst_tag_list_get_int(tags, "cropped_area_image_height",
735 &metadata->cropped_area_image_height);
736 gst_tag_list_get_int(tags, "cropped_area_left",
737 &metadata->cropped_area_left);
738 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
739 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
740 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
741 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
745 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
748 /* macro for better code readability */
749 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
751 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
752 if (string != NULL) { \
753 SECURE_LOGD("update tag string : %s", string); \
754 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
755 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
756 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
757 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
758 mm_player_set_attribute((MMHandleType)player, NULL,\
759 playertag, new_string, strlen(new_string), NULL); \
760 MMPLAYER_FREEIF(new_string); \
762 mm_player_set_attribute((MMHandleType)player, NULL,\
763 playertag, string, strlen(string), NULL); \
765 MMPLAYER_FREEIF(string); \
770 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
772 GstSample *sample = NULL;\
773 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
774 GstMapInfo info = GST_MAP_INFO_INIT;\
775 buffer = gst_sample_get_buffer(sample);\
776 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
777 LOGD("failed to get image data from tag");\
778 gst_sample_unref(sample);\
781 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
782 MMPLAYER_FREEIF(player->album_art);\
783 player->album_art = (gchar *)g_malloc(info.size);\
784 if (player->album_art) {\
785 memcpy(player->album_art, info.data, info.size);\
786 mm_player_set_attribute((MMHandleType)player, NULL,\
787 playertag, (void *)player->album_art, info.size, NULL); \
788 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
789 msg_param.data = (void *)player->album_art;\
790 msg_param.size = info.size;\
791 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
792 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
795 gst_buffer_unmap(buffer, &info);\
796 gst_sample_unref(sample);\
800 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
802 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
805 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
806 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
807 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
808 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
809 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
811 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
812 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
813 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
814 mm_player_set_attribute((MMHandleType)player, NULL,\
815 "content_audio_bitrate", v_uint, NULL); \
816 player->bitrate[track_type] = v_uint; \
817 player->total_bitrate = 0; \
818 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
819 player->total_bitrate += player->bitrate[i]; \
820 mm_player_set_attribute((MMHandleType)player, NULL,\
821 playertag, player->total_bitrate, NULL); \
822 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
823 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
824 player->maximum_bitrate[track_type] = v_uint; \
825 player->total_maximum_bitrate = 0; \
826 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
827 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
828 mm_player_set_attribute((MMHandleType)player, NULL,\
829 playertag, player->total_maximum_bitrate, NULL); \
830 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
832 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
839 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
841 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
843 string = g_strdup_printf("%d", g_date_get_year(date));\
844 mm_player_set_attribute((MMHandleType)player, NULL,\
845 playertag, string, strlen(string), NULL); \
846 SECURE_LOGD("metainfo year : %s", string);\
847 MMPLAYER_FREEIF(string);\
853 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
856 if (datetime != NULL) {\
857 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
858 mm_player_set_attribute((MMHandleType)player, NULL,\
859 playertag, string, strlen(string), NULL); \
860 SECURE_LOGD("metainfo year : %s", string);\
861 MMPLAYER_FREEIF(string);\
862 gst_date_time_unref(datetime);\
868 GstTagList *tag_list = NULL;
873 GstDateTime *datetime = NULL;
875 GstBuffer *buffer = NULL;
877 MMMessageParamType msg_param = {0, };
879 /* currently not used. but those are needed for above macro */
880 //guint64 v_uint64 = 0;
881 //gdouble v_double = 0;
883 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
885 /* get tag list from gst message */
886 gst_message_parse_tag(msg, &tag_list);
888 /* store tags to player attributes */
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
890 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
891 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
892 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
893 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
894 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
896 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
899 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
901 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
902 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
903 MMPLAYER_UPDATE_TAG_LOCK(player);
904 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
905 MMPLAYER_UPDATE_TAG_UNLOCK(player);
906 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
908 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
909 if (player->video360_metadata.is_spherical == -1) {
910 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
911 mm_player_set_attribute((MMHandleType)player, NULL,
912 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
913 if (player->video360_metadata.is_spherical == 1) {
914 LOGD("This is spherical content for 360 playback.");
915 player->is_content_spherical = TRUE;
917 LOGD("This is not spherical content");
918 player->is_content_spherical = FALSE;
921 if (player->video360_metadata.projection_type_string) {
922 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
923 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
925 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
926 player->is_content_spherical = player->is_video360_enabled = FALSE;
930 if (player->video360_metadata.stereo_mode_string) {
931 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
932 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
933 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
934 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
935 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
936 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
938 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
939 player->is_content_spherical = player->is_video360_enabled = FALSE;
945 gst_tag_list_unref(tag_list);
950 /* if retval is FALSE, it will be dropped for perfomance. */
952 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
954 gboolean retval = FALSE;
956 if (!(player->pipeline && player->pipeline->mainbin)) {
957 LOGE("player pipeline handle is null");
961 switch (GST_MESSAGE_TYPE(message)) {
962 case GST_MESSAGE_TAG:
963 case GST_MESSAGE_EOS:
964 case GST_MESSAGE_ERROR:
965 case GST_MESSAGE_WARNING:
966 case GST_MESSAGE_CLOCK_LOST:
967 case GST_MESSAGE_NEW_CLOCK:
968 case GST_MESSAGE_ELEMENT:
969 case GST_MESSAGE_DURATION_CHANGED:
970 case GST_MESSAGE_ASYNC_START:
973 case GST_MESSAGE_ASYNC_DONE:
974 case GST_MESSAGE_STATE_CHANGED:
975 /* we only handle messages from pipeline */
976 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
981 case GST_MESSAGE_BUFFERING:
983 gint buffer_percent = 0;
986 gst_message_parse_buffering(message, &buffer_percent);
987 if (buffer_percent != MAX_BUFFER_PERCENT) {
988 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
992 if (!MMPLAYER_CMD_TRYLOCK(player)) {
993 LOGW("can't get cmd lock, send msg to bus");
997 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
998 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
999 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1002 MMPLAYER_CMD_UNLOCK(player);
1015 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1017 guint64 data_size = 0;
1018 gint64 pos_nsec = 0;
1020 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1022 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1024 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1025 data_size = player->http_content_size;
1028 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1029 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1035 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1037 int ret = MM_ERROR_NONE;
1038 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1039 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1040 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1041 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1043 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1044 LOGW("do nothing for buffering msg");
1045 ret = MM_ERROR_PLAYER_INVALID_STATE;
1049 prev_state = MMPLAYER_PREV_STATE(player);
1050 current_state = MMPLAYER_CURRENT_STATE(player);
1051 target_state = MMPLAYER_TARGET_STATE(player);
1052 pending_state = MMPLAYER_PENDING_STATE(player);
1054 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1055 MMPLAYER_STATE_GET_NAME(prev_state),
1056 MMPLAYER_STATE_GET_NAME(current_state),
1057 MMPLAYER_STATE_GET_NAME(pending_state),
1058 MMPLAYER_STATE_GET_NAME(target_state),
1059 player->streamer->buffering_state);
1061 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1062 /* NOTE : if buffering has done, player has to go to target state. */
1063 switch (target_state) {
1064 case MM_PLAYER_STATE_PAUSED:
1066 switch (pending_state) {
1067 case MM_PLAYER_STATE_PLAYING:
1068 _mmplayer_gst_pause(player, TRUE);
1071 case MM_PLAYER_STATE_PAUSED:
1072 LOGD("player is already going to paused state, there is nothing to do.");
1075 case MM_PLAYER_STATE_NONE:
1076 case MM_PLAYER_STATE_NULL:
1077 case MM_PLAYER_STATE_READY:
1079 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1085 case MM_PLAYER_STATE_PLAYING:
1087 switch (pending_state) {
1088 case MM_PLAYER_STATE_NONE:
1090 if (current_state != MM_PLAYER_STATE_PLAYING)
1091 _mmplayer_gst_resume(player, TRUE);
1095 case MM_PLAYER_STATE_PAUSED:
1096 /* NOTE: It should be worked as asynchronously.
1097 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1099 if (current_state == MM_PLAYER_STATE_PLAYING) {
1100 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1101 * The current state should be changed to paused purposely to prevent state conflict.
1103 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1105 _mmplayer_gst_resume(player, TRUE);
1108 case MM_PLAYER_STATE_PLAYING:
1109 LOGD("player is already going to playing state, there is nothing to do.");
1112 case MM_PLAYER_STATE_NULL:
1113 case MM_PLAYER_STATE_READY:
1115 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1121 case MM_PLAYER_STATE_NULL:
1122 case MM_PLAYER_STATE_READY:
1123 case MM_PLAYER_STATE_NONE:
1125 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1129 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1130 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1132 switch (pending_state) {
1133 case MM_PLAYER_STATE_NONE:
1135 if (current_state != MM_PLAYER_STATE_PAUSED) {
1136 /* rtsp streaming pause makes rtsp server stop sending data. */
1137 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1138 LOGD("set pause state during buffering");
1139 _mmplayer_gst_pause(player, TRUE);
1145 case MM_PLAYER_STATE_PLAYING:
1146 /* rtsp streaming pause makes rtsp server stop sending data. */
1147 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1148 _mmplayer_gst_pause(player, TRUE);
1151 case MM_PLAYER_STATE_PAUSED:
1154 case MM_PLAYER_STATE_NULL:
1155 case MM_PLAYER_STATE_READY:
1157 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1166 static stream_variant_t *
1167 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1169 stream_variant_t *var_info = NULL;
1170 g_return_val_if_fail(self != NULL, NULL);
1172 var_info = g_new0(stream_variant_t, 1);
1173 if (!var_info) return NULL;
1174 var_info->bandwidth = self->bandwidth;
1175 var_info->width = self->width;
1176 var_info->height = self->height;
1181 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1187 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1188 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1190 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1191 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1192 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1194 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1195 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1196 player->http_content_size = (bytes > 0) ? bytes : 0;
1199 /* handling audio clip which has vbr. means duration is keep changing */
1200 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1209 __mmplayer_eos_timer_cb(gpointer u_data)
1211 mmplayer_t *player = NULL;
1212 MMHandleType attrs = 0;
1215 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1217 player = (mmplayer_t *)u_data;
1218 attrs = MMPLAYER_GET_ATTRS(player);
1220 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1224 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1225 if (ret_value != MM_ERROR_NONE)
1226 LOGE("seeking to 0 failed in repeat play");
1229 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1232 /* we are returning FALSE as we need only one posting */
1237 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1239 MMPLAYER_RETURN_IF_FAIL(player);
1241 /* post now if delay is zero */
1242 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1243 LOGD("eos delay is zero. posting EOS now");
1244 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1246 if (player->audio_decoded_cb)
1247 _mmplayer_cancel_eos_timer(player);
1252 /* cancel if existing */
1253 _mmplayer_cancel_eos_timer(player);
1255 /* init new timeout */
1256 /* NOTE : consider give high priority to this timer */
1257 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1259 player->eos_timer = g_timeout_add(delay_in_ms,
1260 __mmplayer_eos_timer_cb, player);
1262 player->context.global_default = g_main_context_default();
1263 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1265 /* check timer is valid. if not, send EOS now */
1266 if (player->eos_timer == 0) {
1267 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1268 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1273 __mmplayer_gst_pending_seek(mmplayer_t *player)
1275 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1276 int ret = MM_ERROR_NONE;
1280 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1282 if (!player->pending_seek.is_pending) {
1283 LOGD("pending seek is not reserved. nothing to do.");
1287 /* check player state if player could pending seek or not. */
1288 current_state = MMPLAYER_CURRENT_STATE(player);
1290 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1291 LOGW("try to pending seek in %s state, try next time. ",
1292 MMPLAYER_STATE_GET_NAME(current_state));
1296 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1298 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1299 if (ret != MM_ERROR_NONE)
1300 LOGE("failed to seek pending postion. just keep staying current position.");
1302 player->pending_seek.is_pending = false;
1310 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1312 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1314 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1316 audiobin = player->pipeline->audiobin; /* can be null */
1317 videobin = player->pipeline->videobin; /* can be null */
1318 textbin = player->pipeline->textbin; /* can be null */
1320 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1322 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1323 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1325 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1326 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1328 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1329 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1335 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1337 mmplayer_gst_element_t *textbin;
1340 MMPLAYER_RETURN_IF_FAIL(player &&
1342 player->pipeline->textbin);
1344 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1346 textbin = player->pipeline->textbin;
1349 LOGD("Drop subtitle text after getting EOS");
1351 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1352 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1354 player->is_subtitle_force_drop = TRUE;
1356 if (player->is_subtitle_force_drop == TRUE) {
1357 LOGD("Enable subtitle data path without drop");
1359 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1360 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1362 LOGD("non-connected with external display");
1364 player->is_subtitle_force_drop = FALSE;
1370 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1372 MMHandleType attrs = 0;
1377 /* NOTE : EOS event is comming multiple time. watch out it */
1378 /* check state. we only process EOS when pipeline state goes to PLAYING */
1379 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1380 LOGD("EOS received on non-playing state. ignoring it");
1384 if (player->pipeline && player->pipeline->textbin)
1385 __mmplayer_drop_subtitle(player, TRUE);
1387 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1388 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1390 /* rewind if repeat count is greater then zero */
1391 /* get play count */
1392 attrs = MMPLAYER_GET_ATTRS(player);
1394 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1396 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1398 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1399 if (player->playback_rate < 0.0) {
1400 player->resumed_by_rewind = TRUE;
1401 _mmplayer_set_mute((MMHandleType)player, false);
1402 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1405 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1408 player->sent_bos = FALSE;
1410 LOGD("do not post eos msg for repeating");
1415 if (player->pipeline)
1416 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1418 /* post eos message to application */
1419 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1421 /* reset last position */
1422 player->last_position = 0;
1429 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1431 GError *error = NULL;
1432 gchar *debug = NULL;
1436 /* generating debug info before returning error */
1437 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1439 /* get error code */
1440 gst_message_parse_error(msg, &error, &debug);
1442 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1443 /* Note : the streaming error from the streaming source is handled
1444 * using __mmplayer_handle_streaming_error.
1446 __mmplayer_handle_streaming_error(player, msg);
1448 /* dump state of all element */
1449 _mmplayer_dump_pipeline_state(player);
1451 /* traslate gst error code to msl error code. then post it
1452 * to application if needed
1454 __mmplayer_handle_gst_error(player, msg, error);
1457 LOGE("error debug : %s", debug);
1460 MMPLAYER_FREEIF(debug);
1461 g_error_free(error);
1468 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1470 MMMessageParamType msg_param = {0, };
1471 int bRet = MM_ERROR_NONE;
1474 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1476 if (!MMPLAYER_IS_STREAMING(player)) {
1477 LOGW("this is not streaming playback.");
1481 MMPLAYER_CMD_LOCK(player);
1483 if (!player->streamer) {
1484 LOGW("Pipeline is shutting down");
1485 MMPLAYER_CMD_UNLOCK(player);
1489 /* ignore the remained buffering message till getting 100% msg */
1490 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1491 gint buffer_percent = 0;
1493 gst_message_parse_buffering(msg, &buffer_percent);
1495 if (buffer_percent == MAX_BUFFER_PERCENT) {
1496 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1497 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1498 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1500 MMPLAYER_CMD_UNLOCK(player);
1504 /* ignore the remained buffering message */
1505 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1506 gint buffer_percent = 0;
1508 gst_message_parse_buffering(msg, &buffer_percent);
1510 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1511 player->streamer->buffering_percent, buffer_percent);
1513 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1514 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1515 player->streamer->buffering_req.is_pre_buffering = FALSE;
1517 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1519 LOGD("interrupted buffering - ignored the remained buffering msg!");
1520 MMPLAYER_CMD_UNLOCK(player);
1525 __mmplayer_update_buffer_setting(player, msg);
1527 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1529 if (bRet == MM_ERROR_NONE) {
1530 msg_param.connection.buffering = player->streamer->buffering_percent;
1531 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1533 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1534 player->pending_resume &&
1535 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1537 player->is_external_subtitle_added_now = FALSE;
1538 player->pending_resume = FALSE;
1539 _mmplayer_resume((MMHandleType)player);
1542 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1543 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1545 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1546 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1547 player->seek_state = MMPLAYER_SEEK_NONE;
1548 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1549 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1550 /* Considering the async state trasition in case of RTSP.
1551 After getting state change gst msg, seek cmpleted msg will be posted. */
1552 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1556 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1557 if (!player->streamer) {
1558 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1559 MMPLAYER_CMD_UNLOCK(player);
1563 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1565 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1566 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1568 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1569 msg_param.connection.buffering = player->streamer->buffering_percent;
1570 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1572 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1575 msg_param.connection.buffering = player->streamer->buffering_percent;
1576 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1579 MMPLAYER_CMD_UNLOCK(player);
1587 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1589 mmplayer_gst_element_t *mainbin;
1590 const GValue *voldstate, *vnewstate, *vpending;
1591 GstState oldstate = GST_STATE_NULL;
1592 GstState newstate = GST_STATE_NULL;
1593 GstState pending = GST_STATE_NULL;
1596 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1598 mainbin = player->pipeline->mainbin;
1600 /* we only handle messages from pipeline */
1601 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1604 /* get state info from msg */
1605 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1606 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1607 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1609 if (!voldstate || !vnewstate) {
1610 LOGE("received msg has wrong format.");
1614 oldstate = (GstState)voldstate->data[0].v_int;
1615 newstate = (GstState)vnewstate->data[0].v_int;
1617 pending = (GstState)vpending->data[0].v_int;
1619 LOGD("state changed [%s] : %s ---> %s final : %s",
1620 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1621 gst_element_state_get_name((GstState)oldstate),
1622 gst_element_state_get_name((GstState)newstate),
1623 gst_element_state_get_name((GstState)pending));
1625 if (newstate == GST_STATE_PLAYING) {
1626 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1628 int retVal = MM_ERROR_NONE;
1629 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1631 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1633 if (MM_ERROR_NONE != retVal)
1634 LOGE("failed to seek pending postion. just keep staying current position.");
1636 player->pending_seek.is_pending = false;
1640 if (oldstate == newstate) {
1641 LOGD("pipeline reports state transition to old state");
1646 case GST_STATE_PAUSED:
1648 gboolean prepare_async = FALSE;
1650 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1651 // managed prepare async case
1652 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1653 LOGD("checking prepare mode for async transition - %d", prepare_async);
1656 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1657 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1659 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1660 _mm_player_streaming_set_content_bitrate(player->streamer,
1661 player->total_maximum_bitrate, player->total_bitrate);
1663 if (player->pending_seek.is_pending) {
1664 LOGW("trying to do pending seek");
1665 MMPLAYER_CMD_LOCK(player);
1666 __mmplayer_gst_pending_seek(player);
1667 MMPLAYER_CMD_UNLOCK(player);
1673 case GST_STATE_PLAYING:
1675 if (MMPLAYER_IS_STREAMING(player)) {
1676 // managed prepare async case when buffering is completed
1677 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1678 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1679 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1680 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1682 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1684 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1685 if (player->streamer->buffering_percent < 100) {
1687 MMMessageParamType msg_param = {0, };
1688 LOGW("Posting Buffering Completed Message to Application !!!");
1690 msg_param.connection.buffering = 100;
1691 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1696 if (player->gapless.stream_changed) {
1697 _mmplayer_update_content_attrs(player, ATTR_ALL);
1698 player->gapless.stream_changed = FALSE;
1701 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1702 player->seek_state = MMPLAYER_SEEK_NONE;
1703 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1707 case GST_STATE_VOID_PENDING:
1708 case GST_STATE_NULL:
1709 case GST_STATE_READY:
1719 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1721 const gchar *structure_name;
1722 gint count = 0, idx = 0;
1725 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1727 if (gst_message_get_structure(msg) == NULL)
1730 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1731 if (!structure_name)
1734 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1736 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1737 const GValue *var_info = NULL;
1739 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1740 if (var_info != NULL) {
1741 if (player->adaptive_info.var_list)
1742 g_list_free_full(player->adaptive_info.var_list, g_free);
1744 /* share addr or copy the list */
1745 player->adaptive_info.var_list =
1746 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1748 count = g_list_length(player->adaptive_info.var_list);
1750 stream_variant_t *temp = NULL;
1752 /* print out for debug */
1753 LOGD("num of variant_info %d", count);
1754 for (idx = 0; idx < count; idx++) {
1755 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1757 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1763 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1764 gint num_buffers = 0;
1765 gint extra_num_buffers = 0;
1767 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1768 LOGD("video_num_buffers : %d", num_buffers);
1769 mm_player_set_attribute((MMHandleType)player, NULL,
1770 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1773 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1774 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1775 mm_player_set_attribute((MMHandleType)player, NULL,
1776 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1781 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1782 _mmplayer_track_update_text_attr_info(player, msg);
1784 /* custom message */
1785 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1786 MMMessageParamType msg_param = {0,};
1787 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1788 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1791 /* custom message for RTSP attribute :
1792 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1793 sdp which has contents info is received when rtsp connection is opened.
1794 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1795 if (!strcmp(structure_name, "rtspsrc_properties")) {
1796 gchar *audio_codec = NULL;
1797 gchar *video_codec = NULL;
1798 gchar *video_frame_size = NULL;
1800 gst_structure_get(gst_message_get_structure(msg),
1801 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1802 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1803 player->streaming_type = _mmplayer_get_stream_service_type(player);
1805 gst_structure_get(gst_message_get_structure(msg),
1806 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1807 LOGD("rtsp_audio_codec : %s", audio_codec);
1809 mm_player_set_attribute((MMHandleType)player, NULL,
1810 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1812 gst_structure_get(gst_message_get_structure(msg),
1813 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1814 LOGD("rtsp_video_codec : %s", video_codec);
1816 mm_player_set_attribute((MMHandleType)player, NULL,
1817 "content_video_codec", video_codec, strlen(video_codec), NULL);
1819 gst_structure_get(gst_message_get_structure(msg),
1820 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1821 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1822 if (video_frame_size) {
1823 char *seperator = strchr(video_frame_size, '-');
1825 char video_width[10] = {0,};
1826 int frame_size_len = strlen(video_frame_size);
1827 int separtor_len = strlen(seperator);
1829 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1832 mm_player_set_attribute((MMHandleType)player, NULL, MM_PLAYER_VIDEO_WIDTH,
1833 atoi(video_width), MM_PLAYER_VIDEO_HEIGHT, atoi(seperator), NULL);
1843 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1845 mmplayer_gst_element_t *mainbin;
1848 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1850 mainbin = player->pipeline->mainbin;
1852 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1854 /* we only handle messages from pipeline */
1855 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1858 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1859 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1860 player->seek_state = MMPLAYER_SEEK_NONE;
1861 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1862 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1863 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1864 LOGD("sync %s state(%s) with parent state(%s)",
1865 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1866 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1867 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1869 /* In case of streaming, pause is required before finishing seeking by buffering.
1870 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1871 Because the buffering state is controlled according to the state transition for force resume,
1872 the decodebin state should be paused as player state. */
1873 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1876 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1877 (player->streamer) &&
1878 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1879 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1880 GstQuery *query = NULL;
1881 gboolean busy = FALSE;
1884 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1885 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1886 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1887 gst_query_parse_buffering_percent(query, &busy, &percent);
1888 gst_query_unref(query);
1890 LOGD("buffered percent(%s): %d",
1891 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1895 __mmplayer_handle_buffering_playback(player);
1898 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1907 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1909 mmplayer_t *player = (mmplayer_t *)(data);
1911 MMPLAYER_RETURN_IF_FAIL(player);
1912 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1914 switch (GST_MESSAGE_TYPE(msg)) {
1915 case GST_MESSAGE_UNKNOWN:
1916 LOGD("unknown message received");
1919 case GST_MESSAGE_EOS:
1920 LOGD("GST_MESSAGE_EOS received");
1921 __mmplayer_gst_handle_eos_message(player, msg);
1924 case GST_MESSAGE_ERROR:
1925 _mmplayer_set_reconfigure_state(player, FALSE);
1926 __mmplayer_gst_handle_error_message(player, msg);
1929 case GST_MESSAGE_WARNING:
1932 GError *error = NULL;
1934 gst_message_parse_warning(msg, &error, &debug);
1936 LOGD("warning : %s", error->message);
1937 LOGD("debug : %s", debug);
1939 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1941 MMPLAYER_FREEIF(debug);
1942 g_error_free(error);
1946 case GST_MESSAGE_TAG:
1948 LOGD("GST_MESSAGE_TAG");
1949 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1950 LOGW("failed to extract tags from gstmessage");
1954 case GST_MESSAGE_BUFFERING:
1955 __mmplayer_gst_handle_buffering_message(player, msg);
1958 case GST_MESSAGE_STATE_CHANGED:
1959 __mmplayer_gst_handle_state_message(player, msg);
1962 case GST_MESSAGE_CLOCK_LOST:
1964 GstClock *clock = NULL;
1965 gboolean need_new_clock = FALSE;
1967 gst_message_parse_clock_lost(msg, &clock);
1968 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1970 if (!player->videodec_linked)
1971 need_new_clock = TRUE;
1972 else if (!player->ini.use_system_clock)
1973 need_new_clock = TRUE;
1975 if (need_new_clock) {
1976 LOGD("Provide clock is TRUE, do pause->resume");
1977 _mmplayer_gst_pause(player, FALSE);
1978 _mmplayer_gst_resume(player, FALSE);
1983 case GST_MESSAGE_NEW_CLOCK:
1985 GstClock *clock = NULL;
1986 gst_message_parse_new_clock(msg, &clock);
1987 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1991 case GST_MESSAGE_ELEMENT:
1992 __mmplayer_gst_handle_element_message(player, msg);
1995 case GST_MESSAGE_DURATION_CHANGED:
1997 LOGD("GST_MESSAGE_DURATION_CHANGED");
1998 if (!__mmplayer_gst_handle_duration(player, msg))
1999 LOGW("failed to update duration");
2003 case GST_MESSAGE_ASYNC_START:
2004 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2007 case GST_MESSAGE_ASYNC_DONE:
2008 __mmplayer_gst_handle_async_done_message(player, msg);
2012 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2013 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2014 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2015 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2016 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2017 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2018 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2019 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2020 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2021 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2022 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2023 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2024 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2025 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2026 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2033 /* should not call 'gst_message_unref(msg)' */
2037 static GstBusSyncReply
2038 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2040 mmplayer_t *player = (mmplayer_t *)data;
2041 GstBusSyncReply reply = GST_BUS_DROP;
2043 if (!(player->pipeline && player->pipeline->mainbin)) {
2044 LOGE("player pipeline handle is null");
2045 return GST_BUS_PASS;
2048 if (!__mmplayer_gst_check_useful_message(player, message)) {
2049 gst_message_unref(message);
2050 return GST_BUS_DROP;
2053 switch (GST_MESSAGE_TYPE(message)) {
2054 case GST_MESSAGE_TAG:
2055 __mmplayer_gst_extract_tag_from_msg(player, message);
2059 GstTagList *tags = NULL;
2061 gst_message_parse_tag(message, &tags);
2063 LOGE("TAGS received from element \"%s\".",
2064 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2066 gst_tag_list_foreach(tags, print_tag, NULL);
2067 gst_tag_list_unref(tags);
2075 case GST_MESSAGE_DURATION_CHANGED:
2076 __mmplayer_gst_handle_duration(player, message);
2078 case GST_MESSAGE_ELEMENT:
2080 const gchar *klass = NULL;
2081 klass = gst_element_factory_get_metadata
2082 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2083 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2084 reply = GST_BUS_PASS;
2087 __mmplayer_gst_handle_element_message(player, message);
2090 case GST_MESSAGE_ASYNC_DONE:
2091 /* NOTE:Don't call gst_callback directly
2092 * because previous frame can be showed even though this message is received for seek.
2095 reply = GST_BUS_PASS;
2099 if (reply == GST_BUS_DROP)
2100 gst_message_unref(message);
2106 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2108 GstElement *appsrc = element;
2109 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2110 GstBuffer *buffer = NULL;
2111 GstFlowReturn ret = GST_FLOW_OK;
2114 MMPLAYER_RETURN_IF_FAIL(element);
2115 MMPLAYER_RETURN_IF_FAIL(buf);
2117 buffer = gst_buffer_new();
2119 if (buf->offset < 0 || buf->len < 0) {
2120 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2124 if (buf->offset >= buf->len) {
2125 LOGD("call eos appsrc");
2126 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2130 if (buf->len - buf->offset < size)
2131 len = buf->len - buf->offset;
2133 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2134 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2135 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2138 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2140 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2146 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2148 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2150 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2152 buf->offset = (int)size;
2158 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2160 mmplayer_t *player = (mmplayer_t *)user_data;
2161 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2162 MMMessageParamType msg_param = {0,};
2163 guint64 current_level_bytes = 0;
2165 MMPLAYER_RETURN_IF_FAIL(player);
2167 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2168 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2169 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2170 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2172 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2176 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2178 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2180 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2181 msg_param.buffer_status.stream_type = stream_type;
2182 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2183 msg_param.buffer_status.bytes = current_level_bytes;
2185 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2189 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2191 mmplayer_t *player = (mmplayer_t *)user_data;
2192 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2193 MMMessageParamType msg_param = {0,};
2194 guint64 current_level_bytes = 0;
2196 MMPLAYER_RETURN_IF_FAIL(player);
2198 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2199 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2200 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2201 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2203 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2207 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2209 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2211 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2212 msg_param.buffer_status.stream_type = stream_type;
2213 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2214 msg_param.buffer_status.bytes = current_level_bytes;
2216 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2220 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2222 mmplayer_t *player = (mmplayer_t *)user_data;
2223 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2224 MMMessageParamType msg_param = {0,};
2226 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2228 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2229 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2230 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2231 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2233 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2237 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2239 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2240 msg_param.seek_data.stream_type = stream_type;
2241 msg_param.seek_data.offset = position;
2243 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2249 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2251 #define MAX_LEN_NAME 20
2253 gboolean ret = FALSE;
2254 GstPad *sinkpad = NULL;
2255 gchar *prefix = NULL;
2256 gchar dec_name[MAX_LEN_NAME] = {0, };
2257 main_element_id_e elem_id = MMPLAYER_M_NUM;
2259 mmplayer_gst_element_t *mainbin = NULL;
2260 GstElement *decodebin = NULL;
2261 GstCaps *dec_caps = NULL;
2265 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2267 player->pipeline->mainbin, FALSE);
2268 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2270 mainbin = player->pipeline->mainbin;
2272 case MM_PLAYER_STREAM_TYPE_AUDIO:
2274 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2276 case MM_PLAYER_STREAM_TYPE_VIDEO:
2278 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2281 LOGE("invalid type %d", type);
2285 if (mainbin[elem_id].gst) {
2286 LOGE("elem(%d) is already created", elem_id);
2290 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2292 /* create decodebin */
2293 decodebin = gst_element_factory_make("decodebin", dec_name);
2295 LOGE("failed to create %s", dec_name);
2299 mainbin[elem_id].id = elem_id;
2300 mainbin[elem_id].gst = decodebin;
2302 /* raw pad handling signal */
2303 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2304 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2306 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2307 before looking for any elements that can handle that stream.*/
2308 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2309 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2311 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2312 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2313 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2315 /* This signal is emitted when a element is added to the bin.*/
2316 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2317 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2319 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2320 LOGE("failed to add new decodebin");
2324 dec_caps = gst_pad_query_caps(srcpad, NULL);
2327 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2329 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2330 gst_caps_unref(dec_caps);
2333 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2335 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2336 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2339 gst_object_unref(GST_OBJECT(sinkpad));
2341 gst_element_sync_state_with_parent(decodebin);
2347 gst_object_unref(GST_OBJECT(sinkpad));
2349 if (mainbin[elem_id].gst) {
2350 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2351 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2352 gst_object_unref(mainbin[elem_id].gst);
2353 mainbin[elem_id].gst = NULL;
2361 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2363 #define MAX_LEN_NAME 20
2364 mmplayer_gst_element_t *mainbin = NULL;
2365 gchar *prefix = NULL;
2366 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2368 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2369 GstElement *src = NULL, *queue = NULL;
2370 GstPad *srcpad = NULL;
2373 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2374 player->pipeline->mainbin, FALSE);
2376 mainbin = player->pipeline->mainbin;
2378 LOGD("type(%d) path is creating", type);
2380 case MM_PLAYER_STREAM_TYPE_AUDIO:
2382 if (mainbin[MMPLAYER_M_SRC].gst)
2383 src_id = MMPLAYER_M_2ND_SRC;
2385 src_id = MMPLAYER_M_SRC;
2386 queue_id = MMPLAYER_M_A_BUFFER;
2388 case MM_PLAYER_STREAM_TYPE_VIDEO:
2390 src_id = MMPLAYER_M_SRC;
2391 queue_id = MMPLAYER_M_V_BUFFER;
2393 case MM_PLAYER_STREAM_TYPE_TEXT:
2394 prefix = "subtitle";
2395 src_id = MMPLAYER_M_SUBSRC;
2396 queue_id = MMPLAYER_M_S_BUFFER;
2399 LOGE("invalid type %d", type);
2403 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2404 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2407 src = gst_element_factory_make("appsrc", src_name);
2409 LOGF("failed to create %s", src_name);
2413 mainbin[src_id].id = src_id;
2414 mainbin[src_id].gst = src;
2416 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2417 "caps", caps, NULL);
2419 /* size of many video frames are larger than default blocksize as 4096 */
2420 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2421 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2423 if (player->media_stream_buffer_max_size[type] > 0)
2424 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2426 if (player->media_stream_buffer_min_percent[type] > 0)
2427 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2429 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2430 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2432 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2433 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2434 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2435 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2436 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2437 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2440 queue = gst_element_factory_make("queue2", queue_name);
2442 LOGE("failed to create %s", queue_name);
2445 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2447 mainbin[queue_id].id = queue_id;
2448 mainbin[queue_id].gst = queue;
2450 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2451 LOGE("failed to add src");
2455 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2456 LOGE("failed to add queue");
2460 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2461 LOGE("failed to link src and queue");
2465 /* create decoder */
2466 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2468 LOGE("failed to get srcpad of queue");
2472 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2473 _mmplayer_gst_create_decoder(player, srcpad, caps);
2475 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2476 LOGE("failed to create decoder");
2477 gst_object_unref(GST_OBJECT(srcpad));
2481 gst_object_unref(GST_OBJECT(srcpad));
2485 if (mainbin[src_id].gst) {
2486 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2487 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2488 gst_object_unref(mainbin[src_id].gst);
2489 mainbin[src_id].gst = NULL;
2492 if (mainbin[queue_id].gst) {
2493 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2494 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2495 gst_object_unref(mainbin[queue_id].gst);
2496 mainbin[queue_id].gst = NULL;
2503 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2505 GstPad *sinkpad = NULL;
2506 GstCaps *caps = NULL;
2507 GstElement *new_element = NULL;
2508 GstStructure *str = NULL;
2509 const gchar *name = NULL;
2511 mmplayer_t *player = (mmplayer_t *)data;
2515 MMPLAYER_RETURN_IF_FAIL(element && pad);
2516 MMPLAYER_RETURN_IF_FAIL(player &&
2518 player->pipeline->mainbin);
2520 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2521 * num_dynamic_pad will decreased after creating a sinkbin.
2523 player->num_dynamic_pad++;
2524 LOGD("stream count inc : %d", player->num_dynamic_pad);
2526 caps = gst_pad_query_caps(pad, NULL);
2527 MMPLAYER_CHECK_NULL(caps);
2529 str = gst_caps_get_structure(caps, 0);
2530 name = gst_structure_get_string(str, "media");
2532 LOGE("cannot get mimetype from structure.");
2536 if (strstr(name, "video")) {
2538 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2540 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2541 if (player->v_stream_caps) {
2542 gst_caps_unref(player->v_stream_caps);
2543 player->v_stream_caps = NULL;
2546 new_element = gst_element_factory_make("fakesink", NULL);
2547 player->num_dynamic_pad--;
2552 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2553 LOGE("failed to autoplug for caps");
2557 gst_caps_unref(caps);
2562 /* excute new_element if created*/
2564 LOGD("adding new element to pipeline");
2566 /* set state to READY before add to bin */
2567 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2569 /* add new element to the pipeline */
2570 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2571 LOGE("failed to add autoplug element to bin");
2575 /* get pad from element */
2576 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2578 LOGE("failed to get sinkpad from autoplug element");
2583 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2584 LOGE("failed to link autoplug element");
2588 gst_object_unref(sinkpad);
2591 /* run. setting PLAYING here since streamming source is live source */
2592 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2596 gst_caps_unref(caps);
2602 STATE_CHANGE_FAILED:
2604 /* FIXIT : take care if new_element has already added to pipeline */
2606 gst_object_unref(GST_OBJECT(new_element));
2609 gst_object_unref(GST_OBJECT(sinkpad));
2612 gst_caps_unref(caps);
2614 /* FIXIT : how to inform this error to MSL ????? */
2615 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2616 * then post an error to application
2621 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2623 mmplayer_t *player = (mmplayer_t *)data;
2627 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2628 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2629 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2630 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2632 * [1] audio and video will be dumped with filesink.
2633 * [2] autoplugging is done by just using pad caps.
2634 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2635 * and the video will be dumped via filesink.
2637 if (player->num_dynamic_pad == 0) {
2638 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2640 if (!_mmplayer_gst_remove_fakesink(player,
2641 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2642 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2643 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2644 * source element are not same. To overcome this situation, this function will called
2645 * several places and several times. Therefore, this is not an error case.
2650 /* create dot before error-return. for debugging */
2651 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2653 player->no_more_pad = TRUE;
2659 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2661 GstElement *element = NULL;
2662 gchar *user_agent = NULL;
2663 MMHandleType attrs = 0;
2666 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2668 /* get profile attribute */
2669 attrs = MMPLAYER_GET_ATTRS(player);
2671 LOGE("failed to get content attribute");
2675 element = gst_element_factory_make("rtspsrc", "rtsp source");
2677 LOGE("failed to create rtspsrc element");
2682 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2684 SECURE_LOGD("user_agent : %s", user_agent);
2686 /* setting property to streaming source */
2687 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2689 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2691 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2692 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2693 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2694 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2701 __mmplayer_gst_make_http_src(mmplayer_t *player)
2703 #define MAX_RETRY_COUNT 10
2704 GstElement *element = NULL;
2705 MMHandleType attrs = 0;
2706 gchar *user_agent, *cookies, **cookie_list;
2707 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2709 user_agent = cookies = NULL;
2713 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2715 /* get profile attribute */
2716 attrs = MMPLAYER_GET_ATTRS(player);
2718 LOGE("failed to get content attribute");
2722 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2724 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2726 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2731 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2732 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2734 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2735 http_timeout = player->ini.http_timeout;
2738 SECURE_LOGD("location : %s", player->profile.uri);
2739 SECURE_LOGD("cookies : %s", cookies);
2740 SECURE_LOGD("user_agent : %s", user_agent);
2741 LOGD("timeout : %d", http_timeout);
2743 /* setting property to streaming source */
2744 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2745 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2746 "retries", MAX_RETRY_COUNT, NULL);
2748 /* parsing cookies */
2749 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2750 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2751 g_strfreev(cookie_list);
2755 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2757 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2758 LOGW("[DASH] this is still experimental feature");
2765 __mmplayer_gst_make_file_src(mmplayer_t *player)
2767 GstElement *element = NULL;
2770 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2772 LOGD("using filesrc for 'file://' handler");
2773 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2774 LOGE("failed to get storage info");
2778 element = gst_element_factory_make("filesrc", "source");
2780 LOGE("failed to create filesrc");
2784 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2791 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2793 mmplayer_t *player = (mmplayer_t *)data;
2795 g_return_val_if_fail(player, FALSE);
2796 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2798 gst_message_ref(msg);
2800 g_mutex_lock(&player->bus_msg_q_lock);
2801 g_queue_push_tail(player->bus_msg_q, msg);
2802 g_mutex_unlock(&player->bus_msg_q_lock);
2804 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2805 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2806 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2810 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2812 mmplayer_t *player = (mmplayer_t *)(data);
2813 GstMessage *msg = NULL;
2817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2819 player->pipeline->mainbin &&
2820 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2823 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2825 LOGE("cannot get BUS from the pipeline");
2829 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2831 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2832 while (!player->bus_msg_thread_exit) {
2833 g_mutex_lock(&player->bus_msg_q_lock);
2834 msg = g_queue_pop_head(player->bus_msg_q);
2835 g_mutex_unlock(&player->bus_msg_q_lock);
2837 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2840 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2841 /* handle the gst msg */
2842 __mmplayer_gst_bus_msg_callback(msg, player);
2843 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2844 gst_message_unref(msg);
2847 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2848 gst_object_unref(GST_OBJECT(bus));
2855 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
2857 gint64 dur_nsec = 0;
2860 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2862 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2863 return MM_ERROR_NONE;
2865 /* NOTE : duration cannot be zero except live streaming.
2866 * Since some element could have some timing problemn with quering duration, try again.
2868 if (player->duration == 0) {
2869 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2870 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2871 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2872 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2873 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2874 player->pending_seek.is_pending = true;
2875 player->pending_seek.pos = position;
2876 player->seek_state = MMPLAYER_SEEK_NONE;
2877 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2878 return MM_ERROR_PLAYER_NO_OP;
2880 player->seek_state = MMPLAYER_SEEK_NONE;
2881 return MM_ERROR_PLAYER_SEEK;
2884 player->duration = dur_nsec;
2887 if (player->duration > 0 && player->duration < position) {
2888 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2889 return MM_ERROR_INVALID_ARGUMENT;
2893 return MM_ERROR_NONE;
2897 __mmplayer_gst_check_seekable(mmplayer_t *player)
2899 GstQuery *query = NULL;
2900 gboolean seekable = FALSE;
2902 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2906 query = gst_query_new_seeking(GST_FORMAT_TIME);
2907 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2908 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2909 gst_query_unref(query);
2912 LOGW("non-seekable content");
2913 player->seek_state = MMPLAYER_SEEK_NONE;
2917 LOGW("failed to get seeking query");
2918 gst_query_unref(query); /* keep seeking operation */
2925 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
2927 GstState element_state = GST_STATE_VOID_PENDING;
2928 GstState element_pending_state = GST_STATE_VOID_PENDING;
2929 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2933 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2934 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2936 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2939 ret = gst_element_set_state(element, state);
2940 if (ret == GST_STATE_CHANGE_FAILURE) {
2941 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2943 /* dump state of all element */
2944 _mmplayer_dump_pipeline_state(player);
2946 return MM_ERROR_PLAYER_INTERNAL;
2949 /* return here so state transition to be done in async mode */
2951 LOGD("async state transition. not waiting for state complete.");
2952 return MM_ERROR_NONE;
2955 /* wait for state transition */
2956 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2957 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2958 LOGE("failed to change [%s] element state to [%s] within %d sec",
2959 GST_ELEMENT_NAME(element),
2960 gst_element_state_get_name(state), timeout);
2962 LOGE(" [%s] state : %s pending : %s",
2963 GST_ELEMENT_NAME(element),
2964 gst_element_state_get_name(element_state),
2965 gst_element_state_get_name(element_pending_state));
2967 /* dump state of all element */
2968 _mmplayer_dump_pipeline_state(player);
2970 return MM_ERROR_PLAYER_INTERNAL;
2973 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2977 return MM_ERROR_NONE;
2981 _mmplayer_gst_start(mmplayer_t *player)
2983 int ret = MM_ERROR_NONE;
2984 gboolean async = FALSE;
2988 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2990 /* NOTE : if SetPosition was called before Start. do it now
2991 * streaming doesn't support it. so it should be always sync
2992 * !!create one more api to check if there is pending seek rather than checking variables
2994 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2995 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2996 ret = _mmplayer_gst_pause(player, FALSE);
2997 if (ret != MM_ERROR_NONE) {
2998 LOGE("failed to set state to PAUSED for pending seek");
3002 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3003 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3004 LOGW("failed to seek pending postion. starting from the begin of content");
3007 LOGD("current state before doing transition");
3008 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3009 MMPLAYER_PRINT_STATE(player);
3011 /* set pipeline state to PLAYING */
3012 ret = _mmplayer_gst_set_state(player,
3013 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3014 if (ret != MM_ERROR_NONE) {
3015 LOGE("failed to set state to PLAYING");
3019 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3021 /* generating debug info before returning error */
3022 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3030 _mmplayer_gst_stop(mmplayer_t *player)
3032 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3033 MMHandleType attrs = 0;
3034 gboolean rewind = FALSE;
3036 int ret = MM_ERROR_NONE;
3040 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3041 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3043 LOGD("current state before doing transition");
3044 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3045 MMPLAYER_PRINT_STATE(player);
3047 attrs = MMPLAYER_GET_ATTRS(player);
3049 LOGE("cannot get content attribute");
3050 return MM_ERROR_PLAYER_INTERNAL;
3053 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3054 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3056 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3057 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3060 if (player->es_player_push_mode)
3061 /* disable the async state transition because there could be no data in the pipeline */
3062 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3065 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3067 if (player->es_player_push_mode) {
3068 /* enable the async state transition as default operation */
3069 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3072 /* return if set_state has failed */
3073 if (ret != MM_ERROR_NONE) {
3074 LOGE("failed to set state.");
3080 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3081 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3082 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3083 LOGW("failed to rewind");
3084 ret = MM_ERROR_PLAYER_SEEK;
3089 player->sent_bos = FALSE;
3091 if (player->es_player_push_mode) //for cloudgame
3094 /* wait for seek to complete */
3095 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3096 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3097 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3099 LOGE("fail to stop player.");
3100 ret = MM_ERROR_PLAYER_INTERNAL;
3101 _mmplayer_dump_pipeline_state(player);
3104 /* generate dot file if enabled */
3105 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3113 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3115 int ret = MM_ERROR_NONE;
3119 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3120 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3122 LOGD("current state before doing transition");
3123 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3124 MMPLAYER_PRINT_STATE(player);
3126 /* set pipeline status to PAUSED */
3127 ret = _mmplayer_gst_set_state(player,
3128 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3133 if (ret != MM_ERROR_NONE) {
3134 GstMessage *msg = NULL;
3135 GTimer *timer = NULL;
3136 gdouble MAX_TIMEOUT_SEC = 3;
3138 LOGE("failed to set state to PAUSED");
3140 if (!player->bus_watcher) {
3141 LOGE("there is no bus msg thread. pipeline is shutting down.");
3145 if (player->msg_posted) {
3146 LOGE("error msg is already posted.");
3150 timer = g_timer_new();
3151 g_timer_start(timer);
3153 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3156 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3158 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3159 GError *error = NULL;
3161 /* parse error code */
3162 gst_message_parse_error(msg, &error, NULL);
3164 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3165 /* Note : the streaming error from the streaming source is handled
3166 * using __mmplayer_handle_streaming_error.
3168 __mmplayer_handle_streaming_error(player, msg);
3171 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3173 if (error->domain == GST_STREAM_ERROR)
3174 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3175 else if (error->domain == GST_RESOURCE_ERROR)
3176 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3177 else if (error->domain == GST_LIBRARY_ERROR)
3178 ret = __mmplayer_gst_handle_library_error(player, error->code);
3179 else if (error->domain == GST_CORE_ERROR)
3180 ret = __mmplayer_gst_handle_core_error(player, error->code);
3182 g_error_free(error);
3184 player->msg_posted = TRUE;
3186 gst_message_unref(msg);
3188 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3190 gst_object_unref(bus);
3191 g_timer_stop(timer);
3192 g_timer_destroy(timer);
3197 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3198 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3199 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3201 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3204 /* generate dot file before returning error */
3205 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3213 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3215 int ret = MM_ERROR_NONE;
3220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3221 MM_ERROR_PLAYER_NOT_INITIALIZED);
3223 LOGD("current state before doing transition");
3224 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3225 MMPLAYER_PRINT_STATE(player);
3228 LOGD("do async state transition to PLAYING");
3230 /* set pipeline state to PLAYING */
3231 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3233 ret = _mmplayer_gst_set_state(player,
3234 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3235 if (ret != MM_ERROR_NONE) {
3236 LOGE("failed to set state to PLAYING");
3241 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3244 /* generate dot file */
3245 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3252 /* sending event to one of sinkelements */
3254 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3256 GstEvent *event2 = NULL;
3257 GList *sinks = NULL;
3258 gboolean res = FALSE;
3261 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3262 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3264 /* While adding subtitles in live feeds seek is getting called.
3265 Adding defensive check in framework layer.*/
3266 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3267 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3268 LOGE("Should not send seek event during live playback");
3273 if (player->play_subtitle)
3274 event2 = gst_event_copy((const GstEvent *)event);
3276 sinks = player->sink_elements;
3278 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3280 if (GST_IS_ELEMENT(sink)) {
3281 /* keep ref to the event */
3282 gst_event_ref(event);
3284 if ((res = gst_element_send_event(sink, event))) {
3285 LOGD("sending event[%s] to sink element [%s] success!",
3286 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3288 /* rtsp case, asyn_done is not called after seek during pause state */
3289 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3290 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3291 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3292 LOGD("RTSP seek completed, after pause state..");
3293 player->seek_state = MMPLAYER_SEEK_NONE;
3294 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3300 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3301 sinks = g_list_next(sinks);
3308 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3309 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3312 sinks = g_list_next(sinks);
3315 /* Note : Textbin is not linked to the video or audio bin.
3316 * It needs to send the event to the text sink seperatelly.
3318 if (player->play_subtitle && player->pipeline) {
3319 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3321 if (GST_IS_ELEMENT(text_sink)) {
3322 /* keep ref to the event */
3323 gst_event_ref(event2);
3325 if ((res = gst_element_send_event(text_sink, event2)))
3326 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3327 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3329 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3330 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3332 gst_event_unref(event2);
3336 gst_event_unref(event);
3344 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3345 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3346 gint64 cur, GstSeekType stop_type, gint64 stop)
3348 GstEvent *event = NULL;
3349 gboolean result = FALSE;
3353 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3355 if (player->pipeline && player->pipeline->textbin)
3356 __mmplayer_drop_subtitle(player, FALSE);
3358 event = gst_event_new_seek(rate, format, flags, cur_type,
3359 cur, stop_type, stop);
3361 result = _mmplayer_gst_send_event_to_sink(player, event);
3369 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3371 int ret = MM_ERROR_NONE;
3372 gint64 pos_nsec = 0;
3373 gboolean accurated = FALSE;
3374 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3377 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3378 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3380 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3381 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3384 ret = __mmplayer_gst_check_duration(player, position);
3385 if (ret != MM_ERROR_NONE) {
3386 LOGE("failed to check duration 0x%X", ret);
3387 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3390 if (!__mmplayer_gst_check_seekable(player))
3391 return MM_ERROR_PLAYER_NO_OP;
3393 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3394 position, player->playback_rate, player->duration);
3396 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3397 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3398 This causes problem is position calculation during normal pause resume scenarios also.
3399 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3400 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3401 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3402 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3403 LOGW("getting current position failed in seek");
3405 player->last_position = pos_nsec;
3406 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3409 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3410 LOGD("not completed seek");
3411 return MM_ERROR_PLAYER_DOING_SEEK;
3414 if (!internal_called)
3415 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3417 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3418 that's why set position through property. */
3419 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3420 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3421 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3422 (!player->videodec_linked) && (!player->audiodec_linked)) {
3424 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3425 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3427 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3428 player->seek_state = MMPLAYER_SEEK_NONE;
3429 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3431 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3433 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3435 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3437 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3438 GST_FORMAT_TIME, seek_flags,
3439 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3440 LOGE("failed to set position");
3445 /* NOTE : store last seeking point to overcome some bad operation
3446 * (returning zero when getting current position) of some elements
3448 player->last_position = position;
3450 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3451 if (player->playback_rate > 1.0)
3452 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3454 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3455 LOGD("buffering should be reset after seeking");
3456 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3457 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3461 return MM_ERROR_NONE;
3464 player->pending_seek.is_pending = true;
3465 player->pending_seek.pos = position;
3467 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3468 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3469 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3470 player->pending_seek.pos);
3472 return MM_ERROR_NONE;
3475 player->seek_state = MMPLAYER_SEEK_NONE;
3476 return MM_ERROR_PLAYER_SEEK;
3480 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3482 #define TRICKPLAY_OFFSET GST_MSECOND
3484 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3485 gint64 pos_nsec = 0;
3486 gboolean ret = TRUE;
3488 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3489 MM_ERROR_PLAYER_NOT_INITIALIZED);
3491 current_state = MMPLAYER_CURRENT_STATE(player);
3493 /* NOTE : query position except paused state to overcome some bad operation
3494 * please refer to below comments in details
3496 if (current_state != MM_PLAYER_STATE_PAUSED)
3497 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3499 /* NOTE : get last point to overcome some bad operation of some elements
3500 *(returning zero when getting current position in paused state
3501 * and when failed to get postion during seeking
3503 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3504 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3506 if (player->playback_rate < 0.0)
3507 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3509 pos_nsec = player->last_position;
3512 pos_nsec = player->last_position;
3514 player->last_position = pos_nsec;
3516 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3519 if (player->duration > 0 && pos_nsec > player->duration)
3520 pos_nsec = player->duration;
3522 player->last_position = pos_nsec;
3525 *position = pos_nsec;
3527 return MM_ERROR_NONE;
3531 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3533 #define STREAMING_IS_FINISHED 0
3534 #define BUFFERING_MAX_PER 100
3535 #define DEFAULT_PER_VALUE -1
3536 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3538 mmplayer_gst_element_t *mainbin = NULL;
3539 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3540 gint64 buffered_total = 0;
3541 gint64 position = 0;
3542 gint buffered_sec = -1;
3543 GstBufferingMode mode = GST_BUFFERING_STREAM;
3544 gint64 content_size_time = player->duration;
3545 guint64 content_size_bytes = player->http_content_size;
3547 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3549 player->pipeline->mainbin,
3550 MM_ERROR_PLAYER_NOT_INITIALIZED);
3552 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3557 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3558 /* and rtsp is not ready yet. */
3559 LOGW("it's only used for http streaming case");
3560 return MM_ERROR_PLAYER_NO_OP;
3563 if (content_size_time <= 0 || content_size_bytes <= 0) {
3564 LOGW("there is no content size");
3565 return MM_ERROR_NONE;
3568 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3569 LOGW("fail to get current position");
3570 return MM_ERROR_NONE;
3573 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3574 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3576 mainbin = player->pipeline->mainbin;
3577 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3579 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3580 GstQuery *query = NULL;
3581 gint byte_in_rate = 0, byte_out_rate = 0;
3582 gint64 estimated_total = 0;
3584 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3585 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3586 LOGW("fail to get buffering query from queue2");
3588 gst_query_unref(query);
3589 return MM_ERROR_NONE;
3592 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3593 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3595 if (mode == GST_BUFFERING_STREAM) {
3596 /* using only queue in case of push mode(ts / mp3) */
3597 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3598 GST_FORMAT_BYTES, &buffered_total)) {
3599 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3600 end_per = 100 * buffered_total / content_size_bytes;
3603 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3605 guint num_of_ranges = 0;
3606 gint64 start_byte = 0, stop_byte = 0;
3608 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3609 if (estimated_total != STREAMING_IS_FINISHED) {
3610 /* buffered size info from queue2 */
3611 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3612 for (idx = 0; idx < num_of_ranges; idx++) {
3613 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3614 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3616 buffered_total += (stop_byte - start_byte);
3619 end_per = BUFFERING_MAX_PER;
3622 gst_query_unref(query);
3625 if (end_per == DEFAULT_PER_VALUE) {
3626 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3628 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3630 /* buffered size info from multiqueue */
3631 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3632 guint curr_size_bytes = 0;
3633 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3634 "curr-size-bytes", &curr_size_bytes, NULL);
3635 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3636 buffered_total += curr_size_bytes;
3639 if (avg_byterate > 0)
3640 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3641 else if (player->total_maximum_bitrate > 0)
3642 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3643 else if (player->total_bitrate > 0)
3644 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3646 if (buffered_sec >= 0)
3647 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3651 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3652 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3654 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3655 buffered_total, buffered_sec, *start_pos, *end_pos);
3657 return MM_ERROR_NONE;
3661 _mmplayer_gst_create_source(mmplayer_t *player)
3663 GstElement *element = NULL;
3666 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3667 player->pipeline->mainbin, NULL);
3669 /* setup source for gapless play */
3670 switch (player->profile.uri_type) {
3672 case MM_PLAYER_URI_TYPE_FILE:
3673 element = __mmplayer_gst_make_file_src(player);
3675 case MM_PLAYER_URI_TYPE_URL_HTTP:
3676 element = __mmplayer_gst_make_http_src(player);
3679 LOGE("not support uri type %d", player->profile.uri_type);
3684 LOGE("failed to create source element");
3693 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3697 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3699 SECURE_LOGD("uri : %s", player->profile.uri);
3701 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3703 if ((player->v_stream_caps) &&
3704 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3705 return MM_ERROR_PLAYER_INTERNAL;
3707 if ((player->a_stream_caps) &&
3708 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3709 return MM_ERROR_PLAYER_INTERNAL;
3711 if ((player->s_stream_caps) &&
3712 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3713 return MM_ERROR_PLAYER_INTERNAL;
3716 return MM_ERROR_NONE;
3720 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3722 mmplayer_gst_element_t *mainbin = NULL;
3723 GstElement *src_elem = NULL;
3724 GstElement *autoplug_elem = NULL;
3725 GList *element_bucket = NULL;
3726 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3729 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3730 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3732 LOGD("uri type %d", player->profile.uri_type);
3734 /* create source element */
3735 switch (player->profile.uri_type) {
3736 case MM_PLAYER_URI_TYPE_URL_RTSP:
3737 src_elem = __mmplayer_gst_make_rtsp_src(player);
3739 case MM_PLAYER_URI_TYPE_URL_HTTP:
3740 src_elem = __mmplayer_gst_make_http_src(player);
3742 case MM_PLAYER_URI_TYPE_FILE:
3743 src_elem = __mmplayer_gst_make_file_src(player);
3745 case MM_PLAYER_URI_TYPE_SS:
3747 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3748 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3750 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3754 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3755 LOGD("get timeout from ini");
3756 http_timeout = player->ini.http_timeout;
3759 /* setting property to streaming source */
3760 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3763 case MM_PLAYER_URI_TYPE_MEM:
3765 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3767 src_elem = gst_element_factory_make("appsrc", "mem-source");
3769 LOGE("failed to create appsrc element");
3773 g_object_set(src_elem, "stream-type", stream_type,
3774 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3776 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3777 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3778 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3779 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3783 LOGE("not support uri type");
3788 LOGE("failed to create source element");
3789 return MM_ERROR_PLAYER_INTERNAL;
3792 mainbin = player->pipeline->mainbin;
3794 /* take source element */
3795 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3797 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3798 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3799 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3801 /* create next element for auto-plugging */
3802 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3803 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3804 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3805 if (!autoplug_elem) {
3806 LOGE("failed to create typefind element");
3810 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3811 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3812 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3813 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3814 autoplug_elem = _mmplayer_gst_make_decodebin(player);
3815 if (!autoplug_elem) {
3816 LOGE("failed to create decodebin");
3820 /* default size of mq in decodebin is 2M
3821 * but it can cause blocking issue during seeking depends on content. */
3822 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3825 if (autoplug_elem) {
3826 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3827 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3828 mainbin[autoplug_elem_id].gst = autoplug_elem;
3830 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3833 /* add elements to pipeline */
3834 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3835 LOGE("failed to add elements to pipeline");
3839 /* linking elements in the bucket by added order. */
3840 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3841 LOGE("failed to link some elements");
3845 /* FIXME: need to check whether this is required or not. */
3846 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
3847 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
3848 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3849 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3850 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3852 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3853 LOGE("failed to create fakesink");
3856 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3858 /* take ownership of fakesink. we are reusing it */
3859 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3861 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3862 LOGE("failed to add fakesink to bin");
3863 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3868 g_list_free(element_bucket);
3871 return MM_ERROR_NONE;
3874 g_list_free(element_bucket);
3876 if (mainbin[MMPLAYER_M_SRC].gst)
3877 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3879 if (mainbin[autoplug_elem_id].gst)
3880 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3882 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3883 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3885 mainbin[MMPLAYER_M_SRC].gst = NULL;
3886 mainbin[autoplug_elem_id].gst = NULL;
3887 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3889 return MM_ERROR_PLAYER_INTERNAL;
3893 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
3896 mmplayer_gst_element_t *mainbin = NULL;
3899 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3900 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3902 mainbin = player->pipeline->mainbin;
3904 /* connect bus callback */
3905 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3907 LOGE("cannot get bus from pipeline");
3908 return MM_ERROR_PLAYER_INTERNAL;
3911 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3912 player->context.thread_default = g_main_context_get_thread_default();
3913 if (player->context.thread_default == NULL) {
3914 player->context.thread_default = g_main_context_default();
3915 LOGD("thread-default context is the global default context");
3917 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3919 /* set sync handler to get tag synchronously */
3920 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3921 gst_object_unref(GST_OBJECT(bus));
3923 /* create gst bus_msb_cb thread */
3924 g_mutex_init(&player->bus_msg_thread_mutex);
3925 g_cond_init(&player->bus_msg_thread_cond);
3926 player->bus_msg_thread_exit = FALSE;
3927 player->bus_msg_thread =
3928 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3929 if (!player->bus_msg_thread) {
3930 LOGE("failed to create gst BUS msg thread");
3931 g_mutex_clear(&player->bus_msg_thread_mutex);
3932 g_cond_clear(&player->bus_msg_thread_cond);
3933 return MM_ERROR_PLAYER_INTERNAL;
3937 return MM_ERROR_NONE;
3941 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
3943 mmplayer_gst_element_t *mainbin = NULL;
3944 MMMessageParamType msg_param = {0,};
3945 GstElement *element = NULL;
3946 MMHandleType attrs = 0;
3948 main_element_id_e elem_idx = MMPLAYER_M_NUM;
3952 if (!player || !player->pipeline || !player->pipeline->mainbin) {
3953 LOGE("player is not initialized");
3957 mainbin = player->pipeline->mainbin;
3958 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
3960 attrs = MMPLAYER_GET_ATTRS(player);
3962 LOGE("fail to get attributes");
3966 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
3968 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
3969 LOGE("failed to parse profile");
3970 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3974 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
3975 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
3976 LOGE("dash or hls is not supportable");
3977 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3981 element = _mmplayer_gst_create_source(player);
3983 LOGE("no source element was created");
3987 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
3988 LOGE("failed to add source element to pipeline");
3989 gst_object_unref(GST_OBJECT(element));
3994 /* take source element */
3995 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3996 mainbin[MMPLAYER_M_SRC].gst = element;
4000 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4001 if (player->streamer == NULL) {
4002 player->streamer = _mm_player_streaming_create();
4003 _mm_player_streaming_initialize(player->streamer, TRUE);
4006 elem_idx = MMPLAYER_M_TYPEFIND;
4007 element = gst_element_factory_make("typefind", "typefinder");
4008 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4009 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4011 elem_idx = MMPLAYER_M_AUTOPLUG;
4012 element = _mmplayer_gst_make_decodebin(player);
4015 /* check autoplug element is OK */
4017 LOGE("can not create element(%d)", elem_idx);
4021 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4022 LOGE("failed to add sinkbin to pipeline");
4023 gst_object_unref(GST_OBJECT(element));
4028 mainbin[elem_idx].id = elem_idx;
4029 mainbin[elem_idx].gst = element;
4031 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4032 LOGE("Failed to link src - autoplug(or typefind)");
4036 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4037 LOGE("Failed to change state of src element");
4041 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4042 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4043 LOGE("Failed to change state of decodebin");
4047 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4048 LOGE("Failed to change state of src element");
4053 player->gapless.stream_changed = TRUE;
4054 player->gapless.running = TRUE;
4060 _mmplayer_set_reconfigure_state(player, FALSE);
4061 if (!player->msg_posted) {
4062 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4063 player->msg_posted = TRUE;