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);
246 src_element_name = GST_ELEMENT_NAME(src_element);
247 if (!src_element_name)
248 return MM_ERROR_PLAYER_INTERNAL;
250 factory = gst_element_get_factory(src_element);
252 return MM_ERROR_PLAYER_INTERNAL;
254 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
256 return MM_ERROR_PLAYER_INTERNAL;
258 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
259 error->code, error->message, src_element_name, klass);
261 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
262 return MM_ERROR_NONE;
264 switch (error->code) {
265 case GST_STREAM_ERROR_DECODE:
266 return __mmplayer_gst_transform_error_decode(player, klass);
267 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
268 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
269 case GST_STREAM_ERROR_WRONG_TYPE:
270 return __mmplayer_gst_transform_error_type(player, src_element);
271 case GST_STREAM_ERROR_FAILED:
272 return __mmplayer_gst_transform_error_failed(player, klass, error);
273 case GST_STREAM_ERROR_DECRYPT:
274 case GST_STREAM_ERROR_DECRYPT_NOKEY:
275 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
276 return __mmplayer_gst_transform_error_decrypt(player, error);
283 return MM_ERROR_PLAYER_INVALID_STREAM;
287 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
289 gint trans_err = MM_ERROR_NONE;
293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
296 case GST_CORE_ERROR_MISSING_PLUGIN:
297 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
298 case GST_CORE_ERROR_STATE_CHANGE:
299 case GST_CORE_ERROR_SEEK:
300 case GST_CORE_ERROR_NOT_IMPLEMENTED:
301 case GST_CORE_ERROR_FAILED:
302 case GST_CORE_ERROR_TOO_LAZY:
303 case GST_CORE_ERROR_PAD:
304 case GST_CORE_ERROR_THREAD:
305 case GST_CORE_ERROR_NEGOTIATION:
306 case GST_CORE_ERROR_EVENT:
307 case GST_CORE_ERROR_CAPS:
308 case GST_CORE_ERROR_TAG:
309 case GST_CORE_ERROR_CLOCK:
310 case GST_CORE_ERROR_DISABLED:
312 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
322 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
324 gint trans_err = MM_ERROR_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
331 case GST_LIBRARY_ERROR_FAILED:
332 case GST_LIBRARY_ERROR_TOO_LAZY:
333 case GST_LIBRARY_ERROR_INIT:
334 case GST_LIBRARY_ERROR_SHUTDOWN:
335 case GST_LIBRARY_ERROR_SETTINGS:
336 case GST_LIBRARY_ERROR_ENCODE:
338 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
348 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
350 gint trans_err = MM_ERROR_NONE;
354 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
358 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
360 case GST_RESOURCE_ERROR_NOT_FOUND:
361 case GST_RESOURCE_ERROR_OPEN_READ:
362 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
363 || MMPLAYER_IS_RTSP_STREAMING(player)) {
364 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
367 case GST_RESOURCE_ERROR_READ:
368 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
369 || MMPLAYER_IS_RTSP_STREAMING(player)) {
370 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
372 } else if (message != NULL && message->src != NULL) {
373 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
374 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
376 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
377 path_type = MMPLAYER_PATH_VOD;
378 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
379 path_type = MMPLAYER_PATH_TEXT;
381 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
382 /* check storage state */
383 storage_get_state(player->storage_info[path_type].id, &storage_state);
384 player->storage_info[path_type].state = storage_state;
385 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
388 case GST_RESOURCE_ERROR_WRITE:
389 case GST_RESOURCE_ERROR_FAILED:
390 case GST_RESOURCE_ERROR_SEEK:
391 case GST_RESOURCE_ERROR_TOO_LAZY:
392 case GST_RESOURCE_ERROR_BUSY:
393 case GST_RESOURCE_ERROR_OPEN_WRITE:
394 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
395 case GST_RESOURCE_ERROR_CLOSE:
396 case GST_RESOURCE_ERROR_SYNC:
397 case GST_RESOURCE_ERROR_SETTINGS:
399 trans_err = MM_ERROR_PLAYER_INTERNAL;
409 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
411 gint trans_err = MM_ERROR_NONE;
415 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
416 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
417 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
419 switch (error->code) {
420 case GST_STREAM_ERROR_FAILED:
421 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
422 case GST_STREAM_ERROR_DECODE:
423 case GST_STREAM_ERROR_WRONG_TYPE:
424 case GST_STREAM_ERROR_DECRYPT:
425 case GST_STREAM_ERROR_DECRYPT_NOKEY:
426 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
427 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
430 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
431 case GST_STREAM_ERROR_TOO_LAZY:
432 case GST_STREAM_ERROR_ENCODE:
433 case GST_STREAM_ERROR_DEMUX:
434 case GST_STREAM_ERROR_MUX:
435 case GST_STREAM_ERROR_FORMAT:
437 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
447 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
449 MMMessageParamType msg_param;
450 gchar *msg_src_element;
454 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
455 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
457 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
459 memset(&msg_param, 0, sizeof(MMMessageParamType));
461 if (error->domain == GST_CORE_ERROR) {
462 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
463 } else if (error->domain == GST_LIBRARY_ERROR) {
464 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
465 } else if (error->domain == GST_RESOURCE_ERROR) {
466 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
467 } else if (error->domain == GST_STREAM_ERROR) {
468 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
470 LOGW("This error domain is not defined.");
472 /* we treat system error as an internal error */
473 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
477 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
479 msg_param.data = (void *)error->message;
481 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
482 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
486 if (msg_param.code == MM_ERROR_NONE)
489 /* skip error to avoid duplicated posting */
490 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
491 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
492 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
493 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
495 /* The error will be handled by mused.
496 * @ref _mmplayer_manage_external_storage_state() */
498 LOGW("storage is removed, skip error post");
502 /* post error to application */
503 if (!player->msg_posted) {
504 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
505 /* don't post more if one was sent already */
506 player->msg_posted = TRUE;
508 LOGD("skip error post because it's sent already.");
517 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
520 MMMessageParamType msg_param;
521 gchar *msg_src_element = NULL;
522 GstStructure *s = NULL;
524 gchar *error_string = NULL;
528 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
529 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
531 s = gst_structure_copy(gst_message_get_structure(message));
534 if (!gst_structure_get_uint(s, "error_id", &error_id))
535 error_id = MMPLAYER_STREAMING_ERROR_NONE;
538 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
539 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
541 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
542 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
544 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
545 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
547 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
548 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
550 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
551 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
553 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
554 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
556 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
557 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
559 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
560 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
562 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
563 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
565 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
566 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
568 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
569 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
571 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
572 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
574 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
575 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
577 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
578 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
580 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
581 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
583 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
584 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
586 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
587 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
589 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
590 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
592 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
593 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
595 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
596 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
598 case MMPLAYER_STREAMING_ERROR_GONE:
599 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
601 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
602 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
604 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
605 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
607 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
608 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
610 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
611 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
613 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
614 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
616 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
617 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
619 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
620 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
622 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
623 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
625 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
626 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
628 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
629 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
631 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
632 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
634 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
635 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
637 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
638 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
640 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
641 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
643 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
644 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
646 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
647 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
649 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
650 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
652 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
653 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
655 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
656 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
658 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
659 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
661 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
662 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
664 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
665 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
667 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
668 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
670 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
671 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
675 gst_structure_free(s);
676 return MM_ERROR_PLAYER_STREAMING_FAIL;
680 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
682 msg_param.data = (void *)error_string;
685 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
687 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
688 msg_src_element, msg_param.code, (char *)msg_param.data);
691 /* post error to application */
692 if (!player->msg_posted) {
693 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
695 /* don't post more if one was sent already */
696 player->msg_posted = TRUE;
698 LOGD("skip error post because it's sent already.");
701 gst_structure_free(s);
702 MMPLAYER_FREEIF(error_string);
710 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
712 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
713 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
714 gst_tag_list_get_string(tags, "stitching_software",
715 &metadata->stitching_software);
716 gst_tag_list_get_string(tags, "projection_type",
717 &metadata->projection_type_string);
718 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
719 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
720 gst_tag_list_get_int(tags, "init_view_heading",
721 &metadata->init_view_heading);
722 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
723 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
724 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
725 gst_tag_list_get_int(tags, "full_pano_width_pixels",
726 &metadata->full_pano_width_pixels);
727 gst_tag_list_get_int(tags, "full_pano_height_pixels",
728 &metadata->full_pano_height_pixels);
729 gst_tag_list_get_int(tags, "cropped_area_image_width",
730 &metadata->cropped_area_image_width);
731 gst_tag_list_get_int(tags, "cropped_area_image_height",
732 &metadata->cropped_area_image_height);
733 gst_tag_list_get_int(tags, "cropped_area_left",
734 &metadata->cropped_area_left);
735 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
736 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
737 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
738 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
742 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
745 /* macro for better code readability */
746 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
748 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
749 if (string != NULL) { \
750 SECURE_LOGD("update tag string : %s", string); \
751 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
752 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
753 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
754 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
755 mm_player_set_attribute((MMHandleType)player, NULL,\
756 playertag, new_string, strlen(new_string), NULL); \
757 MMPLAYER_FREEIF(new_string); \
759 mm_player_set_attribute((MMHandleType)player, NULL,\
760 playertag, string, strlen(string), NULL); \
762 MMPLAYER_FREEIF(string); \
767 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
769 GstSample *sample = NULL;\
770 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
771 GstMapInfo info = GST_MAP_INFO_INIT;\
772 buffer = gst_sample_get_buffer(sample);\
773 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
774 LOGD("failed to get image data from tag");\
775 gst_sample_unref(sample);\
778 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
779 MMPLAYER_FREEIF(player->album_art);\
780 player->album_art = (gchar *)g_malloc(info.size);\
781 if (player->album_art) {\
782 memcpy(player->album_art, info.data, info.size);\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, (void *)player->album_art, info.size, NULL); \
785 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
786 msg_param.data = (void *)player->album_art;\
787 msg_param.size = info.size;\
788 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
789 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
792 gst_buffer_unmap(buffer, &info);\
793 gst_sample_unref(sample);\
797 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
799 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
802 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
803 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
804 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
805 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
806 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
808 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
809 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
810 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
811 mm_player_set_attribute((MMHandleType)player, NULL,\
812 "content_audio_bitrate", v_uint, NULL); \
813 player->bitrate[track_type] = v_uint; \
814 player->total_bitrate = 0; \
815 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
816 player->total_bitrate += player->bitrate[i]; \
817 mm_player_set_attribute((MMHandleType)player, NULL,\
818 playertag, player->total_bitrate, NULL); \
819 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
820 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
821 player->maximum_bitrate[track_type] = v_uint; \
822 player->total_maximum_bitrate = 0; \
823 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
824 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
825 mm_player_set_attribute((MMHandleType)player, NULL,\
826 playertag, player->total_maximum_bitrate, NULL); \
827 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
829 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
836 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
838 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
840 string = g_strdup_printf("%d", g_date_get_year(date));\
841 mm_player_set_attribute((MMHandleType)player, NULL,\
842 playertag, string, strlen(string), NULL); \
843 SECURE_LOGD("metainfo year : %s", string);\
844 MMPLAYER_FREEIF(string);\
850 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
852 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
853 if (datetime != NULL) {\
854 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
855 mm_player_set_attribute((MMHandleType)player, NULL,\
856 playertag, string, strlen(string), NULL); \
857 SECURE_LOGD("metainfo year : %s", string);\
858 MMPLAYER_FREEIF(string);\
859 gst_date_time_unref(datetime);\
865 GstTagList *tag_list = NULL;
870 GstDateTime *datetime = NULL;
872 GstBuffer *buffer = NULL;
874 MMMessageParamType msg_param = {0, };
876 /* currently not used. but those are needed for above macro */
877 //guint64 v_uint64 = 0;
878 //gdouble v_double = 0;
880 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
882 /* get tag list from gst message */
883 gst_message_parse_tag(msg, &tag_list);
885 /* store tags to player attributes */
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
887 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
888 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
890 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
891 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
892 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
893 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
894 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
896 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
898 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
899 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
900 MMPLAYER_UPDATE_TAG_LOCK(player);
901 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
902 MMPLAYER_UPDATE_TAG_UNLOCK(player);
903 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
905 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
906 if (player->video360_metadata.is_spherical == -1) {
907 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
908 mm_player_set_attribute((MMHandleType)player, NULL,
909 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
910 if (player->video360_metadata.is_spherical == 1) {
911 LOGD("This is spherical content for 360 playback.");
912 player->is_content_spherical = TRUE;
914 LOGD("This is not spherical content");
915 player->is_content_spherical = FALSE;
918 if (player->video360_metadata.projection_type_string) {
919 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
920 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
922 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
923 player->is_content_spherical = player->is_video360_enabled = FALSE;
927 if (player->video360_metadata.stereo_mode_string) {
928 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
929 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
930 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
931 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
932 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
933 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
935 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
936 player->is_content_spherical = player->is_video360_enabled = FALSE;
942 gst_tag_list_unref(tag_list);
947 /* if retval is FALSE, it will be dropped for perfomance. */
949 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
951 gboolean retval = FALSE;
953 if (!(player->pipeline && player->pipeline->mainbin)) {
954 LOGE("player pipeline handle is null");
958 switch (GST_MESSAGE_TYPE(message)) {
959 case GST_MESSAGE_TAG:
960 case GST_MESSAGE_EOS:
961 case GST_MESSAGE_ERROR:
962 case GST_MESSAGE_WARNING:
963 case GST_MESSAGE_CLOCK_LOST:
964 case GST_MESSAGE_NEW_CLOCK:
965 case GST_MESSAGE_ELEMENT:
966 case GST_MESSAGE_DURATION_CHANGED:
967 case GST_MESSAGE_ASYNC_START:
970 case GST_MESSAGE_ASYNC_DONE:
971 case GST_MESSAGE_STATE_CHANGED:
972 /* we only handle messages from pipeline */
973 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
978 case GST_MESSAGE_BUFFERING:
980 gint buffer_percent = 0;
983 gst_message_parse_buffering(message, &buffer_percent);
984 if (buffer_percent != MAX_BUFFER_PERCENT) {
985 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
989 if (!MMPLAYER_CMD_TRYLOCK(player)) {
990 LOGW("can't get cmd lock, send msg to bus");
994 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
995 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
996 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
999 MMPLAYER_CMD_UNLOCK(player);
1012 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1014 guint64 data_size = 0;
1015 gint64 pos_nsec = 0;
1017 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1019 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1021 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1022 data_size = player->http_content_size;
1025 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1026 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1032 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1034 int ret = MM_ERROR_NONE;
1035 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1036 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1037 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1038 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1040 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1041 LOGW("do nothing for buffering msg");
1042 ret = MM_ERROR_PLAYER_INVALID_STATE;
1046 prev_state = MMPLAYER_PREV_STATE(player);
1047 current_state = MMPLAYER_CURRENT_STATE(player);
1048 target_state = MMPLAYER_TARGET_STATE(player);
1049 pending_state = MMPLAYER_PENDING_STATE(player);
1051 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1052 MMPLAYER_STATE_GET_NAME(prev_state),
1053 MMPLAYER_STATE_GET_NAME(current_state),
1054 MMPLAYER_STATE_GET_NAME(pending_state),
1055 MMPLAYER_STATE_GET_NAME(target_state),
1056 player->streamer->buffering_state);
1058 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1059 /* NOTE : if buffering has done, player has to go to target state. */
1060 switch (target_state) {
1061 case MM_PLAYER_STATE_PAUSED:
1063 switch (pending_state) {
1064 case MM_PLAYER_STATE_PLAYING:
1065 _mmplayer_gst_pause(player, TRUE);
1068 case MM_PLAYER_STATE_PAUSED:
1069 LOGD("player is already going to paused state, there is nothing to do.");
1072 case MM_PLAYER_STATE_NONE:
1073 case MM_PLAYER_STATE_NULL:
1074 case MM_PLAYER_STATE_READY:
1076 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1082 case MM_PLAYER_STATE_PLAYING:
1084 switch (pending_state) {
1085 case MM_PLAYER_STATE_NONE:
1087 if (current_state != MM_PLAYER_STATE_PLAYING)
1088 _mmplayer_gst_resume(player, TRUE);
1092 case MM_PLAYER_STATE_PAUSED:
1093 /* NOTE: It should be worked as asynchronously.
1094 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1096 if (current_state == MM_PLAYER_STATE_PLAYING) {
1097 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1098 * The current state should be changed to paused purposely to prevent state conflict.
1100 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1102 _mmplayer_gst_resume(player, TRUE);
1105 case MM_PLAYER_STATE_PLAYING:
1106 LOGD("player is already going to playing state, there is nothing to do.");
1109 case MM_PLAYER_STATE_NULL:
1110 case MM_PLAYER_STATE_READY:
1112 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1118 case MM_PLAYER_STATE_NULL:
1119 case MM_PLAYER_STATE_READY:
1120 case MM_PLAYER_STATE_NONE:
1122 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1126 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1127 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1129 switch (pending_state) {
1130 case MM_PLAYER_STATE_NONE:
1132 if (current_state != MM_PLAYER_STATE_PAUSED) {
1133 /* rtsp streaming pause makes rtsp server stop sending data. */
1134 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1135 LOGD("set pause state during buffering");
1136 _mmplayer_gst_pause(player, TRUE);
1142 case MM_PLAYER_STATE_PLAYING:
1143 /* rtsp streaming pause makes rtsp server stop sending data. */
1144 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1145 _mmplayer_gst_pause(player, TRUE);
1148 case MM_PLAYER_STATE_PAUSED:
1151 case MM_PLAYER_STATE_NULL:
1152 case MM_PLAYER_STATE_READY:
1154 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1163 static stream_variant_t *
1164 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1166 stream_variant_t *var_info = NULL;
1167 g_return_val_if_fail(self != NULL, NULL);
1169 var_info = g_new0(stream_variant_t, 1);
1170 if (!var_info) return NULL;
1171 var_info->bandwidth = self->bandwidth;
1172 var_info->width = self->width;
1173 var_info->height = self->height;
1178 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1184 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1185 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1187 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1188 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1189 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1191 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1192 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1193 player->http_content_size = (bytes > 0) ? bytes : 0;
1196 /* handling audio clip which has vbr. means duration is keep changing */
1197 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1206 __mmplayer_eos_timer_cb(gpointer u_data)
1208 mmplayer_t *player = NULL;
1209 MMHandleType attrs = 0;
1212 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1214 player = (mmplayer_t *)u_data;
1215 attrs = MMPLAYER_GET_ATTRS(player);
1217 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1221 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1222 if (ret_value != MM_ERROR_NONE)
1223 LOGE("seeking to 0 failed in repeat play");
1226 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1229 /* we are returning FALSE as we need only one posting */
1234 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1236 MMPLAYER_RETURN_IF_FAIL(player);
1238 /* post now if delay is zero */
1239 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1240 LOGD("eos delay is zero. posting EOS now");
1241 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1243 if (player->audio_decoded_cb)
1244 _mmplayer_cancel_eos_timer(player);
1249 /* cancel if existing */
1250 _mmplayer_cancel_eos_timer(player);
1252 /* init new timeout */
1253 /* NOTE : consider give high priority to this timer */
1254 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1256 player->eos_timer = g_timeout_add(delay_in_ms,
1257 __mmplayer_eos_timer_cb, player);
1259 player->context.global_default = g_main_context_default();
1260 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1262 /* check timer is valid. if not, send EOS now */
1263 if (player->eos_timer == 0) {
1264 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1265 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1270 __mmplayer_gst_pending_seek(mmplayer_t *player)
1272 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1273 int ret = MM_ERROR_NONE;
1277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1279 if (!player->pending_seek.is_pending) {
1280 LOGD("pending seek is not reserved. nothing to do.");
1284 /* check player state if player could pending seek or not. */
1285 current_state = MMPLAYER_CURRENT_STATE(player);
1287 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1288 LOGW("try to pending seek in %s state, try next time. ",
1289 MMPLAYER_STATE_GET_NAME(current_state));
1293 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1295 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1296 if (ret != MM_ERROR_NONE)
1297 LOGE("failed to seek pending postion. just keep staying current position.");
1299 player->pending_seek.is_pending = false;
1307 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1309 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1311 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1313 audiobin = player->pipeline->audiobin; /* can be null */
1314 videobin = player->pipeline->videobin; /* can be null */
1315 textbin = player->pipeline->textbin; /* can be null */
1317 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1319 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1320 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1322 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1323 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1325 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1326 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1332 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1334 mmplayer_gst_element_t *textbin;
1337 MMPLAYER_RETURN_IF_FAIL(player &&
1339 player->pipeline->textbin);
1341 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1343 textbin = player->pipeline->textbin;
1346 LOGD("Drop subtitle text after getting EOS");
1348 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1349 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1351 player->is_subtitle_force_drop = TRUE;
1353 if (player->is_subtitle_force_drop == TRUE) {
1354 LOGD("Enable subtitle data path without drop");
1356 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1357 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1359 LOGD("non-connected with external display");
1361 player->is_subtitle_force_drop = FALSE;
1367 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1369 MMHandleType attrs = 0;
1374 /* NOTE : EOS event is comming multiple time. watch out it */
1375 /* check state. we only process EOS when pipeline state goes to PLAYING */
1376 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1377 LOGD("EOS received on non-playing state. ignoring it");
1381 if (player->pipeline && player->pipeline->textbin)
1382 __mmplayer_drop_subtitle(player, TRUE);
1384 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1385 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1387 /* rewind if repeat count is greater then zero */
1388 /* get play count */
1389 attrs = MMPLAYER_GET_ATTRS(player);
1391 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1393 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1395 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1396 if (player->playback_rate < 0.0) {
1397 player->resumed_by_rewind = TRUE;
1398 _mmplayer_set_mute((MMHandleType)player, false);
1399 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1402 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1405 player->sent_bos = FALSE;
1407 LOGD("do not post eos msg for repeating");
1412 if (player->pipeline)
1413 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1415 /* post eos message to application */
1416 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1418 /* reset last position */
1419 player->last_position = 0;
1426 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1428 GError *error = NULL;
1429 gchar *debug = NULL;
1433 /* generating debug info before returning error */
1434 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1436 /* get error code */
1437 gst_message_parse_error(msg, &error, &debug);
1439 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1440 /* Note : the streaming error from the streaming source is handled
1441 * using __mmplayer_handle_streaming_error.
1443 __mmplayer_handle_streaming_error(player, msg);
1445 /* dump state of all element */
1446 _mmplayer_dump_pipeline_state(player);
1448 /* traslate gst error code to msl error code. then post it
1449 * to application if needed
1451 __mmplayer_handle_gst_error(player, msg, error);
1454 LOGE("error debug : %s", debug);
1457 MMPLAYER_FREEIF(debug);
1458 g_error_free(error);
1465 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1467 MMMessageParamType msg_param = {0, };
1468 int bRet = MM_ERROR_NONE;
1471 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1473 if (!MMPLAYER_IS_STREAMING(player)) {
1474 LOGW("this is not streaming playback.");
1478 MMPLAYER_CMD_LOCK(player);
1480 if (!player->streamer) {
1481 LOGW("Pipeline is shutting down");
1482 MMPLAYER_CMD_UNLOCK(player);
1486 /* ignore the remained buffering message till getting 100% msg */
1487 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1488 gint buffer_percent = 0;
1490 gst_message_parse_buffering(msg, &buffer_percent);
1492 if (buffer_percent == MAX_BUFFER_PERCENT) {
1493 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1494 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1495 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1497 MMPLAYER_CMD_UNLOCK(player);
1501 /* ignore the remained buffering message */
1502 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1503 gint buffer_percent = 0;
1505 gst_message_parse_buffering(msg, &buffer_percent);
1507 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1508 player->streamer->buffering_percent, buffer_percent);
1510 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1511 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1512 player->streamer->buffering_req.is_pre_buffering = FALSE;
1514 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1516 LOGD("interrupted buffering - ignored the remained buffering msg!");
1517 MMPLAYER_CMD_UNLOCK(player);
1522 __mmplayer_update_buffer_setting(player, msg);
1524 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1526 if (bRet == MM_ERROR_NONE) {
1527 msg_param.connection.buffering = player->streamer->buffering_percent;
1528 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1530 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1531 player->pending_resume &&
1532 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1534 player->is_external_subtitle_added_now = FALSE;
1535 player->pending_resume = FALSE;
1536 _mmplayer_resume((MMHandleType)player);
1539 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1540 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1542 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1543 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1544 player->seek_state = MMPLAYER_SEEK_NONE;
1545 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1546 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1547 /* Considering the async state trasition in case of RTSP.
1548 After getting state change gst msg, seek cmpleted msg will be posted. */
1549 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1553 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1554 if (!player->streamer) {
1555 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1556 MMPLAYER_CMD_UNLOCK(player);
1560 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1562 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1563 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1565 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1566 msg_param.connection.buffering = player->streamer->buffering_percent;
1567 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1569 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1572 msg_param.connection.buffering = player->streamer->buffering_percent;
1573 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1576 MMPLAYER_CMD_UNLOCK(player);
1584 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1586 mmplayer_gst_element_t *mainbin;
1587 const GValue *voldstate, *vnewstate, *vpending;
1588 GstState oldstate = GST_STATE_NULL;
1589 GstState newstate = GST_STATE_NULL;
1590 GstState pending = GST_STATE_NULL;
1593 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1595 mainbin = player->pipeline->mainbin;
1597 /* we only handle messages from pipeline */
1598 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1601 /* get state info from msg */
1602 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1603 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1604 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1606 if (!voldstate || !vnewstate) {
1607 LOGE("received msg has wrong format.");
1611 oldstate = (GstState)voldstate->data[0].v_int;
1612 newstate = (GstState)vnewstate->data[0].v_int;
1614 pending = (GstState)vpending->data[0].v_int;
1616 LOGD("state changed [%s] : %s ---> %s final : %s",
1617 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1618 gst_element_state_get_name((GstState)oldstate),
1619 gst_element_state_get_name((GstState)newstate),
1620 gst_element_state_get_name((GstState)pending));
1622 if (newstate == GST_STATE_PLAYING) {
1623 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1625 int retVal = MM_ERROR_NONE;
1626 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1628 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1630 if (MM_ERROR_NONE != retVal)
1631 LOGE("failed to seek pending postion. just keep staying current position.");
1633 player->pending_seek.is_pending = false;
1637 if (oldstate == newstate) {
1638 LOGD("pipeline reports state transition to old state");
1643 case GST_STATE_PAUSED:
1645 gboolean prepare_async = FALSE;
1647 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1648 // managed prepare async case
1649 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1650 LOGD("checking prepare mode for async transition - %d", prepare_async);
1653 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1654 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1656 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1657 _mm_player_streaming_set_content_bitrate(player->streamer,
1658 player->total_maximum_bitrate, player->total_bitrate);
1660 if (player->pending_seek.is_pending) {
1661 LOGW("trying to do pending seek");
1662 MMPLAYER_CMD_LOCK(player);
1663 __mmplayer_gst_pending_seek(player);
1664 MMPLAYER_CMD_UNLOCK(player);
1670 case GST_STATE_PLAYING:
1672 if (MMPLAYER_IS_STREAMING(player)) {
1673 // managed prepare async case when buffering is completed
1674 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1675 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1676 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1677 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1679 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1681 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1682 if (player->streamer->buffering_percent < 100) {
1684 MMMessageParamType msg_param = {0, };
1685 LOGW("Posting Buffering Completed Message to Application !!!");
1687 msg_param.connection.buffering = 100;
1688 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1693 if (player->gapless.stream_changed) {
1694 _mmplayer_update_content_attrs(player, ATTR_ALL);
1695 player->gapless.stream_changed = FALSE;
1698 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1699 player->seek_state = MMPLAYER_SEEK_NONE;
1700 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1704 case GST_STATE_VOID_PENDING:
1705 case GST_STATE_NULL:
1706 case GST_STATE_READY:
1716 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1718 const gchar *structure_name;
1719 gint count = 0, idx = 0;
1722 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1724 if (gst_message_get_structure(msg) == NULL)
1727 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1728 if (!structure_name)
1731 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1733 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1734 const GValue *var_info = NULL;
1736 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1737 if (var_info != NULL) {
1738 if (player->adaptive_info.var_list)
1739 g_list_free_full(player->adaptive_info.var_list, g_free);
1741 /* share addr or copy the list */
1742 player->adaptive_info.var_list =
1743 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1745 count = g_list_length(player->adaptive_info.var_list);
1747 stream_variant_t *temp = NULL;
1749 /* print out for debug */
1750 LOGD("num of variant_info %d", count);
1751 for (idx = 0; idx < count; idx++) {
1752 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1754 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1760 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1761 gint num_buffers = 0;
1762 gint extra_num_buffers = 0;
1764 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1765 LOGD("video_num_buffers : %d", num_buffers);
1766 mm_player_set_attribute((MMHandleType)player, NULL,
1767 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1770 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1771 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1772 mm_player_set_attribute((MMHandleType)player, NULL,
1773 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1778 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1779 _mmplayer_track_update_text_attr_info(player, msg);
1781 /* custom message */
1782 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1783 MMMessageParamType msg_param = {0,};
1784 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1785 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1788 /* custom message for RTSP attribute :
1789 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1790 sdp which has contents info is received when rtsp connection is opened.
1791 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1792 if (!strcmp(structure_name, "rtspsrc_properties")) {
1793 gchar *audio_codec = NULL;
1794 gchar *video_codec = NULL;
1795 gchar *video_frame_size = NULL;
1797 gst_structure_get(gst_message_get_structure(msg),
1798 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1799 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1800 player->streaming_type = _mmplayer_get_stream_service_type(player);
1802 gst_structure_get(gst_message_get_structure(msg),
1803 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1804 LOGD("rtsp_audio_codec : %s", audio_codec);
1806 mm_player_set_attribute((MMHandleType)player, NULL,
1807 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1809 gst_structure_get(gst_message_get_structure(msg),
1810 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1811 LOGD("rtsp_video_codec : %s", video_codec);
1813 mm_player_set_attribute((MMHandleType)player, NULL,
1814 "content_video_codec", video_codec, strlen(video_codec), NULL);
1816 gst_structure_get(gst_message_get_structure(msg),
1817 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1818 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1819 if (video_frame_size) {
1820 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1821 mm_player_set_attribute((MMHandleType)player, NULL,
1822 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1823 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1825 g_strfreev(res_str);
1834 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1836 mmplayer_gst_element_t *mainbin;
1839 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1841 mainbin = player->pipeline->mainbin;
1843 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1845 /* we only handle messages from pipeline */
1846 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1849 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1850 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1851 player->seek_state = MMPLAYER_SEEK_NONE;
1852 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1853 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1854 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1855 LOGD("sync %s state(%s) with parent state(%s)",
1856 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1857 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1858 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1860 /* In case of streaming, pause is required before finishing seeking by buffering.
1861 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1862 Because the buffering state is controlled according to the state transition for force resume,
1863 the decodebin state should be paused as player state. */
1864 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1867 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1868 (player->streamer) &&
1869 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1870 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1871 GstQuery *query = NULL;
1872 gboolean busy = FALSE;
1875 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1876 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1877 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1878 gst_query_parse_buffering_percent(query, &busy, &percent);
1879 gst_query_unref(query);
1881 LOGD("buffered percent(%s): %d",
1882 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1886 __mmplayer_handle_buffering_playback(player);
1889 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1898 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1900 mmplayer_t *player = (mmplayer_t *)(data);
1902 MMPLAYER_RETURN_IF_FAIL(player);
1903 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1905 switch (GST_MESSAGE_TYPE(msg)) {
1906 case GST_MESSAGE_UNKNOWN:
1907 LOGD("unknown message received");
1910 case GST_MESSAGE_EOS:
1911 LOGD("GST_MESSAGE_EOS received");
1912 __mmplayer_gst_handle_eos_message(player, msg);
1915 case GST_MESSAGE_ERROR:
1916 _mmplayer_set_reconfigure_state(player, FALSE);
1917 __mmplayer_gst_handle_error_message(player, msg);
1920 case GST_MESSAGE_WARNING:
1923 GError *error = NULL;
1925 gst_message_parse_warning(msg, &error, &debug);
1927 LOGD("warning : %s", error->message);
1928 LOGD("debug : %s", debug);
1930 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1932 MMPLAYER_FREEIF(debug);
1933 g_error_free(error);
1937 case GST_MESSAGE_TAG:
1939 LOGD("GST_MESSAGE_TAG");
1940 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1941 LOGW("failed to extract tags from gstmessage");
1945 case GST_MESSAGE_BUFFERING:
1946 __mmplayer_gst_handle_buffering_message(player, msg);
1949 case GST_MESSAGE_STATE_CHANGED:
1950 __mmplayer_gst_handle_state_message(player, msg);
1953 case GST_MESSAGE_CLOCK_LOST:
1955 GstClock *clock = NULL;
1956 gboolean need_new_clock = FALSE;
1958 gst_message_parse_clock_lost(msg, &clock);
1959 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1961 if (!player->videodec_linked)
1962 need_new_clock = TRUE;
1963 else if (!player->ini.use_system_clock)
1964 need_new_clock = TRUE;
1966 if (need_new_clock) {
1967 LOGD("Provide clock is TRUE, do pause->resume");
1968 _mmplayer_gst_pause(player, FALSE);
1969 _mmplayer_gst_resume(player, FALSE);
1974 case GST_MESSAGE_NEW_CLOCK:
1976 GstClock *clock = NULL;
1977 gst_message_parse_new_clock(msg, &clock);
1978 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1982 case GST_MESSAGE_ELEMENT:
1983 __mmplayer_gst_handle_element_message(player, msg);
1986 case GST_MESSAGE_DURATION_CHANGED:
1988 LOGD("GST_MESSAGE_DURATION_CHANGED");
1989 if (!__mmplayer_gst_handle_duration(player, msg))
1990 LOGW("failed to update duration");
1994 case GST_MESSAGE_ASYNC_START:
1995 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1998 case GST_MESSAGE_ASYNC_DONE:
1999 __mmplayer_gst_handle_async_done_message(player, msg);
2003 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2004 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2005 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2006 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2007 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2008 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2009 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2010 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2011 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2012 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2013 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2014 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2015 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2016 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2017 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2024 /* should not call 'gst_message_unref(msg)' */
2028 static GstBusSyncReply
2029 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2031 mmplayer_t *player = (mmplayer_t *)data;
2032 GstBusSyncReply reply = GST_BUS_DROP;
2034 if (!(player->pipeline && player->pipeline->mainbin)) {
2035 LOGE("player pipeline handle is null");
2036 return GST_BUS_PASS;
2039 if (!__mmplayer_gst_check_useful_message(player, message)) {
2040 gst_message_unref(message);
2041 return GST_BUS_DROP;
2044 switch (GST_MESSAGE_TYPE(message)) {
2045 case GST_MESSAGE_TAG:
2046 __mmplayer_gst_extract_tag_from_msg(player, message);
2050 GstTagList *tags = NULL;
2052 gst_message_parse_tag(message, &tags);
2054 LOGE("TAGS received from element \"%s\".",
2055 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2057 gst_tag_list_foreach(tags, print_tag, NULL);
2058 gst_tag_list_unref(tags);
2066 case GST_MESSAGE_DURATION_CHANGED:
2067 __mmplayer_gst_handle_duration(player, message);
2069 case GST_MESSAGE_ELEMENT:
2071 const gchar *klass = NULL;
2072 klass = gst_element_factory_get_metadata
2073 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2074 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2075 reply = GST_BUS_PASS;
2078 __mmplayer_gst_handle_element_message(player, message);
2081 case GST_MESSAGE_ASYNC_DONE:
2082 /* NOTE:Don't call gst_callback directly
2083 * because previous frame can be showed even though this message is received for seek.
2086 reply = GST_BUS_PASS;
2090 if (reply == GST_BUS_DROP)
2091 gst_message_unref(message);
2097 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2099 GstElement *appsrc = element;
2100 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2101 GstBuffer *buffer = NULL;
2102 GstFlowReturn ret = GST_FLOW_OK;
2105 MMPLAYER_RETURN_IF_FAIL(element);
2106 MMPLAYER_RETURN_IF_FAIL(buf);
2108 buffer = gst_buffer_new();
2110 if (buf->offset < 0 || buf->len < 0) {
2111 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2115 if (buf->offset >= buf->len) {
2116 LOGD("call eos appsrc");
2117 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2121 if (buf->len - buf->offset < size)
2122 len = buf->len - buf->offset;
2124 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2125 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2126 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2129 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2131 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2137 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2139 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2141 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2143 buf->offset = (int)size;
2149 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2151 mmplayer_t *player = (mmplayer_t *)user_data;
2152 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2153 MMMessageParamType msg_param = {0,};
2154 guint64 current_level_bytes = 0;
2156 MMPLAYER_RETURN_IF_FAIL(player);
2158 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2159 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2160 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2161 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2163 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2167 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2169 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2171 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2172 msg_param.buffer_status.stream_type = stream_type;
2173 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2174 msg_param.buffer_status.bytes = current_level_bytes;
2176 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2180 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2182 mmplayer_t *player = (mmplayer_t *)user_data;
2183 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2184 MMMessageParamType msg_param = {0,};
2185 guint64 current_level_bytes = 0;
2187 MMPLAYER_RETURN_IF_FAIL(player);
2189 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2190 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2191 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2192 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2194 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2198 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2200 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2202 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2203 msg_param.buffer_status.stream_type = stream_type;
2204 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2205 msg_param.buffer_status.bytes = current_level_bytes;
2207 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2211 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2213 mmplayer_t *player = (mmplayer_t *)user_data;
2214 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2215 MMMessageParamType msg_param = {0,};
2217 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2219 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2220 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2221 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2222 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2224 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2228 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2230 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2231 msg_param.seek_data.stream_type = stream_type;
2232 msg_param.seek_data.offset = position;
2234 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2240 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2242 #define MAX_LEN_NAME 20
2244 gboolean ret = FALSE;
2245 GstPad *sinkpad = NULL;
2246 gchar *prefix = NULL;
2247 gchar dec_name[MAX_LEN_NAME] = {0, };
2248 main_element_id_e elem_id = MMPLAYER_M_NUM;
2250 mmplayer_gst_element_t *mainbin = NULL;
2251 GstElement *decodebin = NULL;
2252 GstCaps *dec_caps = NULL;
2256 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2258 player->pipeline->mainbin, FALSE);
2259 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2261 mainbin = player->pipeline->mainbin;
2263 case MM_PLAYER_STREAM_TYPE_AUDIO:
2265 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2267 case MM_PLAYER_STREAM_TYPE_VIDEO:
2269 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2272 LOGE("invalid type %d", type);
2276 if (mainbin[elem_id].gst) {
2277 LOGE("elem(%d) is already created", elem_id);
2281 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2283 /* create decodebin */
2284 decodebin = gst_element_factory_make("decodebin", dec_name);
2286 LOGE("failed to create %s", dec_name);
2290 mainbin[elem_id].id = elem_id;
2291 mainbin[elem_id].gst = decodebin;
2293 /* raw pad handling signal */
2294 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2295 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2297 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2298 before looking for any elements that can handle that stream.*/
2299 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2300 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2302 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2303 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2304 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2306 /* This signal is emitted when a element is added to the bin.*/
2307 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2308 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2310 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2311 LOGE("failed to add new decodebin");
2315 dec_caps = gst_pad_query_caps(srcpad, NULL);
2318 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2320 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2321 gst_caps_unref(dec_caps);
2324 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2326 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2327 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2330 gst_object_unref(GST_OBJECT(sinkpad));
2332 gst_element_sync_state_with_parent(decodebin);
2338 gst_object_unref(GST_OBJECT(sinkpad));
2340 if (mainbin[elem_id].gst) {
2341 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2342 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2343 gst_object_unref(mainbin[elem_id].gst);
2344 mainbin[elem_id].gst = NULL;
2352 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2354 #define MAX_LEN_NAME 20
2355 mmplayer_gst_element_t *mainbin = NULL;
2356 gchar *prefix = NULL;
2357 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2359 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2360 GstElement *src = NULL, *queue = NULL;
2361 GstPad *srcpad = NULL;
2364 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2365 player->pipeline->mainbin, FALSE);
2367 mainbin = player->pipeline->mainbin;
2369 LOGD("type(%d) path is creating", type);
2371 case MM_PLAYER_STREAM_TYPE_AUDIO:
2373 if (mainbin[MMPLAYER_M_SRC].gst)
2374 src_id = MMPLAYER_M_2ND_SRC;
2376 src_id = MMPLAYER_M_SRC;
2377 queue_id = MMPLAYER_M_A_BUFFER;
2379 case MM_PLAYER_STREAM_TYPE_VIDEO:
2381 src_id = MMPLAYER_M_SRC;
2382 queue_id = MMPLAYER_M_V_BUFFER;
2384 case MM_PLAYER_STREAM_TYPE_TEXT:
2385 prefix = "subtitle";
2386 src_id = MMPLAYER_M_SUBSRC;
2387 queue_id = MMPLAYER_M_S_BUFFER;
2390 LOGE("invalid type %d", type);
2394 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2395 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2398 src = gst_element_factory_make("appsrc", src_name);
2400 LOGF("failed to create %s", src_name);
2404 mainbin[src_id].id = src_id;
2405 mainbin[src_id].gst = src;
2407 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2408 "caps", caps, NULL);
2410 /* size of many video frames are larger than default blocksize as 4096 */
2411 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2412 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2414 if (player->media_stream_buffer_max_size[type] > 0)
2415 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2417 if (player->media_stream_buffer_min_percent[type] > 0)
2418 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2420 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2421 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2423 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2424 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2425 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2426 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2427 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2428 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2431 queue = gst_element_factory_make("queue2", queue_name);
2433 LOGE("failed to create %s", queue_name);
2436 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2438 mainbin[queue_id].id = queue_id;
2439 mainbin[queue_id].gst = queue;
2441 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2442 LOGE("failed to add src");
2446 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2447 LOGE("failed to add queue");
2451 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2452 LOGE("failed to link src and queue");
2456 /* create decoder */
2457 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2459 LOGE("failed to get srcpad of queue");
2463 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2464 _mmplayer_gst_create_decoder(player, srcpad, caps);
2466 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2467 LOGE("failed to create decoder");
2468 gst_object_unref(GST_OBJECT(srcpad));
2472 gst_object_unref(GST_OBJECT(srcpad));
2476 if (mainbin[src_id].gst) {
2477 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2478 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2479 gst_object_unref(mainbin[src_id].gst);
2480 mainbin[src_id].gst = NULL;
2483 if (mainbin[queue_id].gst) {
2484 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2485 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2486 gst_object_unref(mainbin[queue_id].gst);
2487 mainbin[queue_id].gst = NULL;
2494 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2496 GstPad *sinkpad = NULL;
2497 GstCaps *caps = NULL;
2498 GstElement *new_element = NULL;
2499 GstStructure *str = NULL;
2500 const gchar *name = NULL;
2502 mmplayer_t *player = (mmplayer_t *)data;
2506 MMPLAYER_RETURN_IF_FAIL(element && pad);
2507 MMPLAYER_RETURN_IF_FAIL(player &&
2509 player->pipeline->mainbin);
2511 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2512 * num_dynamic_pad will decreased after creating a sinkbin.
2514 player->num_dynamic_pad++;
2515 LOGD("stream count inc : %d", player->num_dynamic_pad);
2517 caps = gst_pad_query_caps(pad, NULL);
2518 MMPLAYER_CHECK_NULL(caps);
2520 str = gst_caps_get_structure(caps, 0);
2521 name = gst_structure_get_string(str, "media");
2523 LOGE("cannot get mimetype from structure.");
2527 if (strstr(name, "video")) {
2529 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2531 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2532 if (player->v_stream_caps) {
2533 gst_caps_unref(player->v_stream_caps);
2534 player->v_stream_caps = NULL;
2537 new_element = gst_element_factory_make("fakesink", NULL);
2538 player->num_dynamic_pad--;
2543 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2544 LOGE("failed to autoplug for caps");
2548 gst_caps_unref(caps);
2553 /* excute new_element if created*/
2555 LOGD("adding new element to pipeline");
2557 /* set state to READY before add to bin */
2558 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2560 /* add new element to the pipeline */
2561 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2562 LOGE("failed to add autoplug element to bin");
2566 /* get pad from element */
2567 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2569 LOGE("failed to get sinkpad from autoplug element");
2574 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2575 LOGE("failed to link autoplug element");
2579 gst_object_unref(sinkpad);
2582 /* run. setting PLAYING here since streamming source is live source */
2583 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2587 gst_caps_unref(caps);
2593 STATE_CHANGE_FAILED:
2595 /* FIXIT : take care if new_element has already added to pipeline */
2597 gst_object_unref(GST_OBJECT(new_element));
2600 gst_object_unref(GST_OBJECT(sinkpad));
2603 gst_caps_unref(caps);
2605 /* FIXIT : how to inform this error to MSL ????? */
2606 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2607 * then post an error to application
2612 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2614 mmplayer_t *player = (mmplayer_t *)data;
2618 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2619 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2620 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2621 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2623 * [1] audio and video will be dumped with filesink.
2624 * [2] autoplugging is done by just using pad caps.
2625 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2626 * and the video will be dumped via filesink.
2628 if (player->num_dynamic_pad == 0) {
2629 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2631 if (!_mmplayer_gst_remove_fakesink(player,
2632 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2633 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2634 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2635 * source element are not same. To overcome this situation, this function will called
2636 * several places and several times. Therefore, this is not an error case.
2641 /* create dot before error-return. for debugging */
2642 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2644 player->no_more_pad = TRUE;
2650 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2652 GstElement *element = NULL;
2653 gchar *user_agent = NULL;
2654 MMHandleType attrs = 0;
2657 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2659 /* get profile attribute */
2660 attrs = MMPLAYER_GET_ATTRS(player);
2662 LOGE("failed to get content attribute");
2666 element = gst_element_factory_make("rtspsrc", "rtsp source");
2668 LOGE("failed to create rtspsrc element");
2673 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2675 SECURE_LOGD("user_agent : %s", user_agent);
2677 /* setting property to streaming source */
2678 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2680 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2682 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2683 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2684 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2685 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2692 __mmplayer_gst_make_http_src(mmplayer_t *player)
2694 #define MAX_RETRY_COUNT 10
2695 GstElement *element = NULL;
2696 MMHandleType attrs = 0;
2697 gchar *user_agent, *cookies, **cookie_list;
2698 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2700 user_agent = cookies = NULL;
2704 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2706 /* get profile attribute */
2707 attrs = MMPLAYER_GET_ATTRS(player);
2709 LOGE("failed to get content attribute");
2713 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2715 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2717 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2722 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2723 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2725 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2726 http_timeout = player->ini.http_timeout;
2729 SECURE_LOGD("location : %s", player->profile.uri);
2730 SECURE_LOGD("cookies : %s", cookies);
2731 SECURE_LOGD("user_agent : %s", user_agent);
2732 LOGD("timeout : %d", http_timeout);
2734 /* setting property to streaming source */
2735 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2736 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2737 "retries", MAX_RETRY_COUNT, NULL);
2739 /* parsing cookies */
2740 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2741 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2742 g_strfreev(cookie_list);
2746 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2748 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2749 LOGW("[DASH] this is still experimental feature");
2756 __mmplayer_gst_make_file_src(mmplayer_t *player)
2758 GstElement *element = NULL;
2761 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2763 LOGD("using filesrc for 'file://' handler");
2764 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2765 LOGE("failed to get storage info");
2769 element = gst_element_factory_make("filesrc", "source");
2771 LOGE("failed to create filesrc");
2775 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2782 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2784 mmplayer_t *player = (mmplayer_t *)data;
2786 g_return_val_if_fail(player, FALSE);
2787 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2788 gst_message_ref(msg);
2790 g_mutex_lock(&player->bus_msg_q_lock);
2791 g_queue_push_tail(player->bus_msg_q, msg);
2792 g_mutex_unlock(&player->bus_msg_q_lock);
2794 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2795 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2796 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2800 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2802 mmplayer_t *player = (mmplayer_t *)(data);
2803 GstMessage *msg = NULL;
2806 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2808 player->pipeline->mainbin &&
2809 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2812 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2814 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2815 while (!player->bus_msg_thread_exit) {
2816 g_mutex_lock(&player->bus_msg_q_lock);
2817 msg = g_queue_pop_head(player->bus_msg_q);
2818 g_mutex_unlock(&player->bus_msg_q_lock);
2820 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2823 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2824 /* handle the gst msg */
2825 __mmplayer_gst_bus_msg_callback(msg, player);
2826 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2827 gst_message_unref(msg);
2830 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2837 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
2839 gint64 dur_nsec = 0;
2842 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2844 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2845 return MM_ERROR_NONE;
2847 /* NOTE : duration cannot be zero except live streaming.
2848 * Since some element could have some timing problemn with quering duration, try again.
2850 if (player->duration == 0) {
2851 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2852 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2853 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2854 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2855 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2856 player->pending_seek.is_pending = true;
2857 player->pending_seek.pos = position;
2858 player->seek_state = MMPLAYER_SEEK_NONE;
2859 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2860 return MM_ERROR_PLAYER_NO_OP;
2862 player->seek_state = MMPLAYER_SEEK_NONE;
2863 return MM_ERROR_PLAYER_SEEK;
2866 player->duration = dur_nsec;
2869 if (player->duration > 0 && player->duration < position) {
2870 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2871 return MM_ERROR_INVALID_ARGUMENT;
2875 return MM_ERROR_NONE;
2879 __mmplayer_gst_check_seekable(mmplayer_t *player)
2881 GstQuery *query = NULL;
2882 gboolean seekable = FALSE;
2884 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2888 query = gst_query_new_seeking(GST_FORMAT_TIME);
2889 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2890 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2891 gst_query_unref(query);
2894 LOGW("non-seekable content");
2895 player->seek_state = MMPLAYER_SEEK_NONE;
2899 LOGW("failed to get seeking query");
2900 gst_query_unref(query); /* keep seeking operation */
2907 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
2909 GstState element_state = GST_STATE_VOID_PENDING;
2910 GstState element_pending_state = GST_STATE_VOID_PENDING;
2911 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2916 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2918 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2921 ret = gst_element_set_state(element, state);
2922 if (ret == GST_STATE_CHANGE_FAILURE) {
2923 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2925 /* dump state of all element */
2926 _mmplayer_dump_pipeline_state(player);
2928 return MM_ERROR_PLAYER_INTERNAL;
2931 /* return here so state transition to be done in async mode */
2933 LOGD("async state transition. not waiting for state complete.");
2934 return MM_ERROR_NONE;
2937 /* wait for state transition */
2938 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2939 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2940 LOGE("failed to change [%s] element state to [%s] within %d sec",
2941 GST_ELEMENT_NAME(element),
2942 gst_element_state_get_name(state), timeout);
2944 LOGE(" [%s] state : %s pending : %s",
2945 GST_ELEMENT_NAME(element),
2946 gst_element_state_get_name(element_state),
2947 gst_element_state_get_name(element_pending_state));
2949 /* dump state of all element */
2950 _mmplayer_dump_pipeline_state(player);
2952 return MM_ERROR_PLAYER_INTERNAL;
2955 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2959 return MM_ERROR_NONE;
2963 _mmplayer_gst_start(mmplayer_t *player)
2965 int ret = MM_ERROR_NONE;
2966 gboolean async = FALSE;
2970 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2972 /* NOTE : if SetPosition was called before Start. do it now
2973 * streaming doesn't support it. so it should be always sync
2974 * !!create one more api to check if there is pending seek rather than checking variables
2976 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2977 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2978 ret = _mmplayer_gst_pause(player, FALSE);
2979 if (ret != MM_ERROR_NONE) {
2980 LOGE("failed to set state to PAUSED for pending seek");
2984 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
2985 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
2986 LOGW("failed to seek pending postion. starting from the begin of content");
2989 LOGD("current state before doing transition");
2990 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2991 MMPLAYER_PRINT_STATE(player);
2993 /* set pipeline state to PLAYING */
2994 ret = _mmplayer_gst_set_state(player,
2995 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2996 if (ret != MM_ERROR_NONE) {
2997 LOGE("failed to set state to PLAYING");
3001 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3003 /* generating debug info before returning error */
3004 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3012 _mmplayer_gst_stop(mmplayer_t *player)
3014 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3015 MMHandleType attrs = 0;
3016 gboolean rewind = FALSE;
3018 int ret = MM_ERROR_NONE;
3022 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3023 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3025 LOGD("current state before doing transition");
3026 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3027 MMPLAYER_PRINT_STATE(player);
3029 attrs = MMPLAYER_GET_ATTRS(player);
3031 LOGE("cannot get content attribute");
3032 return MM_ERROR_PLAYER_INTERNAL;
3035 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3036 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3038 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3039 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3042 if (player->es_player_push_mode)
3043 /* disable the async state transition because there could be no data in the pipeline */
3044 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3047 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3049 if (player->es_player_push_mode) {
3050 /* enable the async state transition as default operation */
3051 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3054 /* return if set_state has failed */
3055 if (ret != MM_ERROR_NONE) {
3056 LOGE("failed to set state.");
3062 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3063 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3064 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3065 LOGW("failed to rewind");
3066 ret = MM_ERROR_PLAYER_SEEK;
3071 player->sent_bos = FALSE;
3073 if (player->es_player_push_mode) //for cloudgame
3076 /* wait for seek to complete */
3077 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3078 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3079 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3081 LOGE("fail to stop player.");
3082 ret = MM_ERROR_PLAYER_INTERNAL;
3083 _mmplayer_dump_pipeline_state(player);
3086 /* generate dot file if enabled */
3087 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3095 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3097 int ret = MM_ERROR_NONE;
3101 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3102 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3104 LOGD("current state before doing transition");
3105 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3106 MMPLAYER_PRINT_STATE(player);
3108 /* set pipeline status to PAUSED */
3109 ret = _mmplayer_gst_set_state(player,
3110 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3115 if (ret != MM_ERROR_NONE) {
3116 GstMessage *msg = NULL;
3117 GTimer *timer = NULL;
3118 gdouble MAX_TIMEOUT_SEC = 3;
3120 LOGE("failed to set state to PAUSED");
3122 if (!player->bus_watcher) {
3123 LOGE("there is no bus msg thread. pipeline is shutting down.");
3127 if (player->msg_posted) {
3128 LOGE("error msg is already posted.");
3132 timer = g_timer_new();
3133 g_timer_start(timer);
3135 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3138 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3140 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3141 GError *error = NULL;
3143 /* parse error code */
3144 gst_message_parse_error(msg, &error, NULL);
3146 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3147 /* Note : the streaming error from the streaming source is handled
3148 * using __mmplayer_handle_streaming_error.
3150 __mmplayer_handle_streaming_error(player, msg);
3153 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3155 if (error->domain == GST_STREAM_ERROR)
3156 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3157 else if (error->domain == GST_RESOURCE_ERROR)
3158 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3159 else if (error->domain == GST_LIBRARY_ERROR)
3160 ret = __mmplayer_gst_handle_library_error(player, error->code);
3161 else if (error->domain == GST_CORE_ERROR)
3162 ret = __mmplayer_gst_handle_core_error(player, error->code);
3164 g_error_free(error);
3166 player->msg_posted = TRUE;
3168 gst_message_unref(msg);
3170 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3172 gst_object_unref(bus);
3173 g_timer_stop(timer);
3174 g_timer_destroy(timer);
3179 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3180 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3181 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3183 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3186 /* generate dot file before returning error */
3187 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3195 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3197 int ret = MM_ERROR_NONE;
3202 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3203 MM_ERROR_PLAYER_NOT_INITIALIZED);
3205 LOGD("current state before doing transition");
3206 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3207 MMPLAYER_PRINT_STATE(player);
3210 LOGD("do async state transition to PLAYING");
3212 /* set pipeline state to PLAYING */
3213 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3215 ret = _mmplayer_gst_set_state(player,
3216 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3217 if (ret != MM_ERROR_NONE) {
3218 LOGE("failed to set state to PLAYING");
3223 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3226 /* generate dot file */
3227 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3234 /* sending event to one of sinkelements */
3236 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3238 GstEvent *event2 = NULL;
3239 GList *sinks = NULL;
3240 gboolean res = FALSE;
3243 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3244 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3246 /* While adding subtitles in live feeds seek is getting called.
3247 Adding defensive check in framework layer.*/
3248 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3249 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3250 LOGE("Should not send seek event during live playback");
3255 if (player->play_subtitle)
3256 event2 = gst_event_copy((const GstEvent *)event);
3258 sinks = player->sink_elements;
3260 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3262 if (GST_IS_ELEMENT(sink)) {
3263 /* keep ref to the event */
3264 gst_event_ref(event);
3266 if ((res = gst_element_send_event(sink, event))) {
3267 LOGD("sending event[%s] to sink element [%s] success!",
3268 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3270 /* rtsp case, asyn_done is not called after seek during pause state */
3271 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3272 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3273 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3274 LOGD("RTSP seek completed, after pause state..");
3275 player->seek_state = MMPLAYER_SEEK_NONE;
3276 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3282 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3283 sinks = g_list_next(sinks);
3290 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3291 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3294 sinks = g_list_next(sinks);
3297 /* Note : Textbin is not linked to the video or audio bin.
3298 * It needs to send the event to the text sink seperatelly.
3300 if (player->play_subtitle && player->pipeline) {
3301 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3303 if (GST_IS_ELEMENT(text_sink)) {
3304 /* keep ref to the event */
3305 gst_event_ref(event2);
3307 if ((res = gst_element_send_event(text_sink, event2)))
3308 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3309 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3311 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3312 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3314 gst_event_unref(event2);
3318 gst_event_unref(event);
3326 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3327 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3328 gint64 cur, GstSeekType stop_type, gint64 stop)
3330 GstEvent *event = NULL;
3331 gboolean result = FALSE;
3335 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3337 if (player->pipeline && player->pipeline->textbin)
3338 __mmplayer_drop_subtitle(player, FALSE);
3340 event = gst_event_new_seek(rate, format, flags, cur_type,
3341 cur, stop_type, stop);
3343 result = _mmplayer_gst_send_event_to_sink(player, event);
3351 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3353 int ret = MM_ERROR_NONE;
3354 gint64 pos_nsec = 0;
3355 gboolean accurated = FALSE;
3356 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3359 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3360 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3362 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3363 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3366 ret = __mmplayer_gst_check_duration(player, position);
3367 if (ret != MM_ERROR_NONE) {
3368 LOGE("failed to check duration 0x%X", ret);
3369 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3372 if (!__mmplayer_gst_check_seekable(player))
3373 return MM_ERROR_PLAYER_NO_OP;
3375 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3376 position, player->playback_rate, player->duration);
3378 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3379 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3380 This causes problem is position calculation during normal pause resume scenarios also.
3381 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3382 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3383 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3384 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3385 LOGW("getting current position failed in seek");
3387 player->last_position = pos_nsec;
3388 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3391 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3392 LOGD("not completed seek");
3393 return MM_ERROR_PLAYER_DOING_SEEK;
3396 if (!internal_called)
3397 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3399 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3400 that's why set position through property. */
3401 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3402 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3403 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3404 (!player->videodec_linked) && (!player->audiodec_linked)) {
3406 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3407 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3409 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3410 player->seek_state = MMPLAYER_SEEK_NONE;
3411 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3413 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3415 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3417 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3419 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3420 GST_FORMAT_TIME, seek_flags,
3421 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3422 LOGE("failed to set position");
3427 /* NOTE : store last seeking point to overcome some bad operation
3428 * (returning zero when getting current position) of some elements
3430 player->last_position = position;
3432 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3433 if (player->playback_rate > 1.0)
3434 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3436 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3437 LOGD("buffering should be reset after seeking");
3438 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3439 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3443 return MM_ERROR_NONE;
3446 player->pending_seek.is_pending = true;
3447 player->pending_seek.pos = position;
3449 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3450 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3451 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3452 player->pending_seek.pos);
3454 return MM_ERROR_NONE;
3457 player->seek_state = MMPLAYER_SEEK_NONE;
3458 return MM_ERROR_PLAYER_SEEK;
3462 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3464 #define TRICKPLAY_OFFSET GST_MSECOND
3466 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3467 gint64 pos_nsec = 0;
3468 gboolean ret = TRUE;
3470 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3471 MM_ERROR_PLAYER_NOT_INITIALIZED);
3473 current_state = MMPLAYER_CURRENT_STATE(player);
3475 /* NOTE : query position except paused state to overcome some bad operation
3476 * please refer to below comments in details
3478 if (current_state != MM_PLAYER_STATE_PAUSED)
3479 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3481 /* NOTE : get last point to overcome some bad operation of some elements
3482 *(returning zero when getting current position in paused state
3483 * and when failed to get postion during seeking
3485 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3486 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3488 if (player->playback_rate < 0.0)
3489 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3491 pos_nsec = player->last_position;
3494 pos_nsec = player->last_position;
3496 player->last_position = pos_nsec;
3498 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3501 if (player->duration > 0 && pos_nsec > player->duration)
3502 pos_nsec = player->duration;
3504 player->last_position = pos_nsec;
3507 *position = pos_nsec;
3509 return MM_ERROR_NONE;
3513 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3515 #define STREAMING_IS_FINISHED 0
3516 #define BUFFERING_MAX_PER 100
3517 #define DEFAULT_PER_VALUE -1
3518 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3520 mmplayer_gst_element_t *mainbin = NULL;
3521 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3522 gint64 buffered_total = 0;
3523 gint64 position = 0;
3524 gint buffered_sec = -1;
3525 GstBufferingMode mode = GST_BUFFERING_STREAM;
3526 gint64 content_size_time = player->duration;
3527 guint64 content_size_bytes = player->http_content_size;
3529 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3531 player->pipeline->mainbin,
3532 MM_ERROR_PLAYER_NOT_INITIALIZED);
3534 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3539 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3540 /* and rtsp is not ready yet. */
3541 LOGW("it's only used for http streaming case");
3542 return MM_ERROR_PLAYER_NO_OP;
3545 if (content_size_time <= 0 || content_size_bytes <= 0) {
3546 LOGW("there is no content size");
3547 return MM_ERROR_NONE;
3550 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3551 LOGW("fail to get current position");
3552 return MM_ERROR_NONE;
3555 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3556 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3558 mainbin = player->pipeline->mainbin;
3559 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3561 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3562 GstQuery *query = NULL;
3563 gint byte_in_rate = 0, byte_out_rate = 0;
3564 gint64 estimated_total = 0;
3566 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3567 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3568 LOGW("fail to get buffering query from queue2");
3570 gst_query_unref(query);
3571 return MM_ERROR_NONE;
3574 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3575 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3577 if (mode == GST_BUFFERING_STREAM) {
3578 /* using only queue in case of push mode(ts / mp3) */
3579 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3580 GST_FORMAT_BYTES, &buffered_total)) {
3581 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3582 end_per = 100 * buffered_total / content_size_bytes;
3585 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3587 guint num_of_ranges = 0;
3588 gint64 start_byte = 0, stop_byte = 0;
3590 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3591 if (estimated_total != STREAMING_IS_FINISHED) {
3592 /* buffered size info from queue2 */
3593 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3594 for (idx = 0; idx < num_of_ranges; idx++) {
3595 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3596 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3598 buffered_total += (stop_byte - start_byte);
3601 end_per = BUFFERING_MAX_PER;
3604 gst_query_unref(query);
3607 if (end_per == DEFAULT_PER_VALUE) {
3608 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3610 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3612 /* buffered size info from multiqueue */
3613 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3614 guint curr_size_bytes = 0;
3615 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3616 "curr-size-bytes", &curr_size_bytes, NULL);
3617 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3618 buffered_total += curr_size_bytes;
3621 if (avg_byterate > 0)
3622 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3623 else if (player->total_maximum_bitrate > 0)
3624 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3625 else if (player->total_bitrate > 0)
3626 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3628 if (buffered_sec >= 0)
3629 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3633 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3634 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3636 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3637 buffered_total, buffered_sec, *start_pos, *end_pos);
3639 return MM_ERROR_NONE;
3643 _mmplayer_gst_create_source(mmplayer_t *player)
3645 GstElement *element = NULL;
3648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3649 player->pipeline->mainbin, NULL);
3651 /* setup source for gapless play */
3652 switch (player->profile.uri_type) {
3654 case MM_PLAYER_URI_TYPE_FILE:
3655 element = __mmplayer_gst_make_file_src(player);
3657 case MM_PLAYER_URI_TYPE_URL_HTTP:
3658 element = __mmplayer_gst_make_http_src(player);
3661 LOGE("not support uri type %d", player->profile.uri_type);
3666 LOGE("failed to create source element");
3675 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3678 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3679 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3681 SECURE_LOGD("uri : %s", player->profile.uri);
3683 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3685 if ((player->v_stream_caps) &&
3686 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3687 return MM_ERROR_PLAYER_INTERNAL;
3689 if ((player->a_stream_caps) &&
3690 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3691 return MM_ERROR_PLAYER_INTERNAL;
3693 if ((player->s_stream_caps) &&
3694 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3695 return MM_ERROR_PLAYER_INTERNAL;
3698 return MM_ERROR_NONE;
3702 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3704 mmplayer_gst_element_t *mainbin = NULL;
3705 GstElement *src_elem = NULL;
3706 GstElement *autoplug_elem = NULL;
3707 GList *element_bucket = NULL;
3708 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3711 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3712 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3714 LOGD("uri type %d", player->profile.uri_type);
3716 /* create source element */
3717 switch (player->profile.uri_type) {
3718 case MM_PLAYER_URI_TYPE_URL_RTSP:
3719 src_elem = __mmplayer_gst_make_rtsp_src(player);
3721 case MM_PLAYER_URI_TYPE_URL_HTTP:
3722 src_elem = __mmplayer_gst_make_http_src(player);
3724 case MM_PLAYER_URI_TYPE_FILE:
3725 src_elem = __mmplayer_gst_make_file_src(player);
3727 case MM_PLAYER_URI_TYPE_SS:
3729 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3730 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3732 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3736 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3737 LOGD("get timeout from ini");
3738 http_timeout = player->ini.http_timeout;
3741 /* setting property to streaming source */
3742 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3745 case MM_PLAYER_URI_TYPE_MEM:
3747 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3749 src_elem = gst_element_factory_make("appsrc", "mem-source");
3751 LOGE("failed to create appsrc element");
3755 g_object_set(src_elem, "stream-type", stream_type,
3756 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3758 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3759 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3760 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3761 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3765 LOGE("not support uri type");
3770 LOGE("failed to create source element");
3771 return MM_ERROR_PLAYER_INTERNAL;
3774 mainbin = player->pipeline->mainbin;
3776 /* take source element */
3777 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3779 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3780 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3781 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3783 /* create next element for auto-plugging */
3784 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3785 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3786 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3787 if (!autoplug_elem) {
3788 LOGE("failed to create typefind element");
3792 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3793 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3794 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3795 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3796 autoplug_elem = _mmplayer_gst_make_decodebin(player);
3797 if (!autoplug_elem) {
3798 LOGE("failed to create decodebin");
3802 /* default size of mq in decodebin is 2M
3803 * but it can cause blocking issue during seeking depends on content. */
3804 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3807 if (autoplug_elem) {
3808 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3809 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3810 mainbin[autoplug_elem_id].gst = autoplug_elem;
3812 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3815 /* add elements to pipeline */
3816 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3817 LOGE("failed to add elements to pipeline");
3821 /* linking elements in the bucket by added order. */
3822 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3823 LOGE("failed to link some elements");
3827 /* FIXME: need to check whether this is required or not. */
3828 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
3829 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
3830 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3831 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3832 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3834 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3835 LOGE("failed to create fakesink");
3838 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3840 /* take ownership of fakesink. we are reusing it */
3841 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3843 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3844 LOGE("failed to add fakesink to bin");
3845 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3850 g_list_free(element_bucket);
3853 return MM_ERROR_NONE;
3856 g_list_free(element_bucket);
3858 if (mainbin[MMPLAYER_M_SRC].gst)
3859 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3861 if (mainbin[autoplug_elem_id].gst)
3862 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3864 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3865 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3867 mainbin[MMPLAYER_M_SRC].gst = NULL;
3868 mainbin[autoplug_elem_id].gst = NULL;
3869 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3871 return MM_ERROR_PLAYER_INTERNAL;
3875 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
3878 mmplayer_gst_element_t *mainbin = NULL;
3881 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3882 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884 mainbin = player->pipeline->mainbin;
3886 /* connect bus callback */
3887 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3889 LOGE("cannot get bus from pipeline");
3890 return MM_ERROR_PLAYER_INTERNAL;
3893 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
3894 (GstBusFunc)__mmplayer_gst_msg_push, player,
3895 (GDestroyNotify)_mmplayer_watcher_removed_notify);
3896 if (player->bus_watcher == 0) {
3897 LOGE("failed to add bus watch");
3898 return MM_ERROR_PLAYER_INTERNAL;
3901 g_mutex_init(&player->bus_watcher_mutex);
3902 g_cond_init(&player->bus_watcher_cond);
3904 player->context.thread_default = g_main_context_get_thread_default();
3905 if (player->context.thread_default == NULL) {
3906 player->context.thread_default = g_main_context_default();
3907 LOGD("thread-default context is the global default context");
3909 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3911 /* set sync handler to get tag synchronously */
3912 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3913 gst_object_unref(GST_OBJECT(bus));
3915 /* create gst bus_msb_cb thread */
3916 g_mutex_init(&player->bus_msg_thread_mutex);
3917 g_cond_init(&player->bus_msg_thread_cond);
3918 player->bus_msg_thread_exit = FALSE;
3919 player->bus_msg_thread =
3920 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3921 if (!player->bus_msg_thread) {
3922 LOGE("failed to create gst BUS msg thread");
3923 g_mutex_clear(&player->bus_msg_thread_mutex);
3924 g_cond_clear(&player->bus_msg_thread_cond);
3925 return MM_ERROR_PLAYER_INTERNAL;
3929 return MM_ERROR_NONE;
3933 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
3935 mmplayer_gst_element_t *mainbin = NULL;
3936 MMMessageParamType msg_param = {0,};
3937 GstElement *element = NULL;
3938 MMHandleType attrs = 0;
3940 main_element_id_e elem_idx = MMPLAYER_M_NUM;
3944 if (!player || !player->pipeline || !player->pipeline->mainbin) {
3945 LOGE("player is not initialized");
3949 mainbin = player->pipeline->mainbin;
3950 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
3952 attrs = MMPLAYER_GET_ATTRS(player);
3954 LOGE("fail to get attributes");
3958 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
3960 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
3961 LOGE("failed to parse profile");
3962 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3966 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
3967 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
3968 LOGE("dash or hls is not supportable");
3969 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3973 element = _mmplayer_gst_create_source(player);
3975 LOGE("no source element was created");
3979 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
3980 LOGE("failed to add source element to pipeline");
3981 gst_object_unref(GST_OBJECT(element));
3986 /* take source element */
3987 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3988 mainbin[MMPLAYER_M_SRC].gst = element;
3992 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3993 if (player->streamer == NULL) {
3994 player->streamer = _mm_player_streaming_create();
3995 _mm_player_streaming_initialize(player->streamer, TRUE);
3998 elem_idx = MMPLAYER_M_TYPEFIND;
3999 element = gst_element_factory_make("typefind", "typefinder");
4000 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4001 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4003 elem_idx = MMPLAYER_M_AUTOPLUG;
4004 element = _mmplayer_gst_make_decodebin(player);
4007 /* check autoplug element is OK */
4009 LOGE("can not create element(%d)", elem_idx);
4013 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4014 LOGE("failed to add sinkbin to pipeline");
4015 gst_object_unref(GST_OBJECT(element));
4020 mainbin[elem_idx].id = elem_idx;
4021 mainbin[elem_idx].gst = element;
4023 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4024 LOGE("Failed to link src - autoplug(or typefind)");
4028 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4029 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4030 LOGE("Failed to change state of decodebin");
4034 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4035 LOGE("Failed to change state of src element");
4040 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4041 LOGE("Failed to change state of src element");
4045 player->gapless.stream_changed = TRUE;
4046 player->gapless.running = TRUE;
4052 _mmplayer_set_reconfigure_state(player, FALSE);
4053 if (!player->msg_posted) {
4054 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4055 player->msg_posted = TRUE;