4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | GLOBAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
48 /*---------------------------------------------------------------------------
49 | IMPORTED VARIABLE DECLARATIONS: |
50 ---------------------------------------------------------------------------*/
52 /*---------------------------------------------------------------------------
53 | IMPORTED FUNCTION DECLARATIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | LOCAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | LOCAL DATA TYPE DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | GLOBAL VARIABLE DEFINITIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | LOCAL VARIABLE DEFINITIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
77 | LOCAL FUNCTION PROTOTYPES: |
78 ---------------------------------------------------------------------------*/
80 /*===========================================================================================
82 | FUNCTION DEFINITIONS |
84 ========================================================================================== */
87 __mmplayer_check_error_posted_from_activated_track(mm_player_t *player, gchar *src_element_name)
89 /* check whether the error is posted from not-activated track or not */
91 gint active_pad_index = 0;
93 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
95 active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
96 LOGD("current active pad index -%d", active_pad_index);
98 if (src_element_name) {
101 if (player->audio_decoders) {
102 GList *adec = player->audio_decoders;
103 for (; adec ; adec = g_list_next(adec)) {
104 gchar *name = adec->data;
106 LOGD("found audio decoder name = %s", name);
107 if (g_strrstr(name, src_element_name)) {
114 LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos);
117 if (active_pad_index != msg_src_pos) {
118 LOGD("skip error because error is posted from no activated track");
126 __mmplayer_gst_transform_error_decode(mm_player_t *player, const char *klass)
128 /* Demuxer can't parse one track because it's corrupted.
129 * So, the decoder for it is not linked.
130 * But, it has one playable track.
132 if (g_strrstr(klass, "Demux")) {
133 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
134 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
135 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
136 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
138 if (player->pipeline->audiobin) { // PCM
139 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
141 LOGD("not found any available codec. Player should be destroyed.");
142 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
147 return MM_ERROR_PLAYER_INVALID_STREAM;
151 __mmplayer_gst_transform_error_type(mm_player_t *player, GstElement *src_element)
153 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
154 LOGE("Not supported subtitle.");
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
157 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
161 __mmplayer_gst_transform_error_failed(mm_player_t *player, const char *klass, GError *error)
163 /* Decoder Custom Message */
164 if (!strstr(error->message, "ongoing"))
165 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
167 if (strncasecmp(klass, "audio", 5)) {
168 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
169 LOGD("Video can keep playing.");
170 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
172 } else if (strncasecmp(klass, "video", 5)) {
173 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
174 LOGD("Audio can keep playing.");
175 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
179 LOGD("not found any available codec. Player should be destroyed.");
180 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
184 __mmplayer_gst_transform_error_decrypt(mm_player_t *player, GError *error)
186 if (strstr(error->message, "rights expired"))
187 return MM_ERROR_PLAYER_DRM_EXPIRED;
188 else if (strstr(error->message, "no rights"))
189 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
190 else if (strstr(error->message, "has future rights"))
191 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
192 else if (strstr(error->message, "opl violation"))
193 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
195 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
198 /* NOTE : decide gstreamer state whether there is some playable track or not. */
200 __mmplayer_gst_transform_gsterror(mm_player_t *player, GstMessage *message, GError *error)
202 gchar *src_element_name = NULL;
203 GstElement *src_element = NULL;
204 GstElementFactory *factory = NULL;
205 const gchar *klass = NULL;
209 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
211 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
212 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
214 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
216 src_element = GST_ELEMENT_CAST(message->src);
218 return MM_ERROR_PLAYER_INTERNAL;
220 src_element_name = GST_ELEMENT_NAME(src_element);
221 if (!src_element_name)
222 return MM_ERROR_PLAYER_INTERNAL;
224 factory = gst_element_get_factory(src_element);
226 return MM_ERROR_PLAYER_INTERNAL;
228 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
230 return MM_ERROR_PLAYER_INTERNAL;
232 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
233 error->code, error->message, src_element_name, klass);
235 if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
236 return MM_ERROR_NONE;
238 switch (error->code) {
239 case GST_STREAM_ERROR_DECODE:
240 return __mmplayer_gst_transform_error_decode(player, klass);
241 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
242 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
243 case GST_STREAM_ERROR_WRONG_TYPE:
244 return __mmplayer_gst_transform_error_type(player, src_element);
245 case GST_STREAM_ERROR_FAILED:
246 return __mmplayer_gst_transform_error_failed(player, klass, error);
247 case GST_STREAM_ERROR_DECRYPT:
248 case GST_STREAM_ERROR_DECRYPT_NOKEY:
249 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
250 return __mmplayer_gst_transform_error_decrypt(player, error);
257 return MM_ERROR_PLAYER_INVALID_STREAM;
261 __mmplayer_gst_handle_core_error(mm_player_t *player, int code)
263 gint trans_err = MM_ERROR_NONE;
267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
270 case GST_CORE_ERROR_MISSING_PLUGIN:
271 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
272 case GST_CORE_ERROR_STATE_CHANGE:
273 case GST_CORE_ERROR_SEEK:
274 case GST_CORE_ERROR_NOT_IMPLEMENTED:
275 case GST_CORE_ERROR_FAILED:
276 case GST_CORE_ERROR_TOO_LAZY:
277 case GST_CORE_ERROR_PAD:
278 case GST_CORE_ERROR_THREAD:
279 case GST_CORE_ERROR_NEGOTIATION:
280 case GST_CORE_ERROR_EVENT:
281 case GST_CORE_ERROR_CAPS:
282 case GST_CORE_ERROR_TAG:
283 case GST_CORE_ERROR_CLOCK:
284 case GST_CORE_ERROR_DISABLED:
286 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
296 __mmplayer_gst_handle_library_error(mm_player_t *player, int code)
298 gint trans_err = MM_ERROR_NONE;
302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
305 case GST_LIBRARY_ERROR_FAILED:
306 case GST_LIBRARY_ERROR_TOO_LAZY:
307 case GST_LIBRARY_ERROR_INIT:
308 case GST_LIBRARY_ERROR_SHUTDOWN:
309 case GST_LIBRARY_ERROR_SETTINGS:
310 case GST_LIBRARY_ERROR_ENCODE:
312 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
322 __mmplayer_gst_handle_resource_error(mm_player_t *player, int code, GstMessage *message)
324 gint trans_err = MM_ERROR_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
331 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
332 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
334 case GST_RESOURCE_ERROR_NOT_FOUND:
335 case GST_RESOURCE_ERROR_OPEN_READ:
336 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
337 || MMPLAYER_IS_RTSP_STREAMING(player)) {
338 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
341 case GST_RESOURCE_ERROR_READ:
342 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
343 || MMPLAYER_IS_RTSP_STREAMING(player)) {
344 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
346 } else if (message != NULL && message->src != NULL) {
347 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
348 MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
350 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
351 path_type = MMPLAYER_PATH_VOD;
352 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
353 path_type = MMPLAYER_PATH_TEXT;
355 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
356 /* check storage state */
357 storage_get_state(player->storage_info[path_type].id, &storage_state);
358 player->storage_info[path_type].state = storage_state;
359 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
362 case GST_RESOURCE_ERROR_WRITE:
363 case GST_RESOURCE_ERROR_FAILED:
364 case GST_RESOURCE_ERROR_SEEK:
365 case GST_RESOURCE_ERROR_TOO_LAZY:
366 case GST_RESOURCE_ERROR_BUSY:
367 case GST_RESOURCE_ERROR_OPEN_WRITE:
368 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
369 case GST_RESOURCE_ERROR_CLOSE:
370 case GST_RESOURCE_ERROR_SYNC:
371 case GST_RESOURCE_ERROR_SETTINGS:
373 trans_err = MM_ERROR_PLAYER_INTERNAL;
383 __mmplayer_gst_handle_stream_error(mm_player_t *player, GError *error, GstMessage *message)
385 gint trans_err = MM_ERROR_NONE;
389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
390 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
391 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
393 switch (error->code) {
394 case GST_STREAM_ERROR_FAILED:
395 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
396 case GST_STREAM_ERROR_DECODE:
397 case GST_STREAM_ERROR_WRONG_TYPE:
398 case GST_STREAM_ERROR_DECRYPT:
399 case GST_STREAM_ERROR_DECRYPT_NOKEY:
400 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
401 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
404 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
405 case GST_STREAM_ERROR_TOO_LAZY:
406 case GST_STREAM_ERROR_ENCODE:
407 case GST_STREAM_ERROR_DEMUX:
408 case GST_STREAM_ERROR_MUX:
409 case GST_STREAM_ERROR_FORMAT:
411 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
421 __mmplayer_handle_gst_error(mm_player_t *player, GstMessage *message, GError *error)
423 MMMessageParamType msg_param;
424 gchar *msg_src_element;
428 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
429 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
431 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
433 memset(&msg_param, 0, sizeof(MMMessageParamType));
435 if (error->domain == GST_CORE_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
437 } else if (error->domain == GST_LIBRARY_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
439 } else if (error->domain == GST_RESOURCE_ERROR) {
440 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
441 } else if (error->domain == GST_STREAM_ERROR) {
442 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
444 LOGW("This error domain is not defined.");
446 /* we treat system error as an internal error */
447 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
451 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
453 msg_param.data = (void *)error->message;
455 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
456 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
460 if (msg_param.code == MM_ERROR_NONE)
463 /* skip error to avoid duplicated posting */
464 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
465 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
466 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
467 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
469 /* The error will be handled by mused.
470 * @ref _mmplayer_manage_external_storage_state() */
472 LOGW("storage is removed, skip error post");
476 /* post error to application */
477 if (!player->msg_posted) {
478 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
479 /* don't post more if one was sent already */
480 player->msg_posted = TRUE;
482 LOGD("skip error post because it's sent already.");
491 __mmplayer_handle_streaming_error(mm_player_t *player, GstMessage *message)
494 MMMessageParamType msg_param;
495 gchar *msg_src_element = NULL;
496 GstStructure *s = NULL;
498 gchar *error_string = NULL;
502 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
503 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
505 s = gst_structure_copy(gst_message_get_structure(message));
508 if (!gst_structure_get_uint(s, "error_id", &error_id))
509 error_id = MMPLAYER_STREAMING_ERROR_NONE;
512 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
515 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
518 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
521 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
524 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
527 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
530 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
533 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
536 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
539 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
542 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
545 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
548 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
551 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
554 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
557 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
560 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
563 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
566 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
569 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
572 case MMPLAYER_STREAMING_ERROR_GONE:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
575 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
578 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
581 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
584 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
587 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
590 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
593 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
596 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
599 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
602 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
605 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
608 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
611 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
614 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
617 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
620 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
623 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
626 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
629 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
632 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
635 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
636 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
638 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
639 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
641 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
642 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
644 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
645 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
649 gst_structure_free(s);
650 return MM_ERROR_PLAYER_STREAMING_FAIL;
654 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
656 msg_param.data = (void *)error_string;
659 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
661 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]",
662 msg_src_element, msg_param.code, (char *)msg_param.data);
665 /* post error to application */
666 if (!player->msg_posted) {
667 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
669 /* don't post more if one was sent already */
670 player->msg_posted = TRUE;
672 LOGD("skip error post because it's sent already.");
675 gst_structure_free(s);
676 MMPLAYER_FREEIF(error_string);
684 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
686 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
687 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
688 gst_tag_list_get_string(tags, "stitching_software",
689 &metadata->stitching_software);
690 gst_tag_list_get_string(tags, "projection_type",
691 &metadata->projection_type_string);
692 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
693 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
694 gst_tag_list_get_int(tags, "init_view_heading",
695 &metadata->init_view_heading);
696 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
697 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
698 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
699 gst_tag_list_get_int(tags, "full_pano_width_pixels",
700 &metadata->full_pano_width_pixels);
701 gst_tag_list_get_int(tags, "full_pano_height_pixels",
702 &metadata->full_pano_height_pixels);
703 gst_tag_list_get_int(tags, "cropped_area_image_width",
704 &metadata->cropped_area_image_width);
705 gst_tag_list_get_int(tags, "cropped_area_image_height",
706 &metadata->cropped_area_image_height);
707 gst_tag_list_get_int(tags, "cropped_area_left",
708 &metadata->cropped_area_left);
709 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
710 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
711 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
712 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
716 __mmplayer_gst_extract_tag_from_msg(mm_player_t *player, GstMessage *msg)
719 /* macro for better code readability */
720 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
722 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
723 if (string != NULL) { \
724 SECURE_LOGD("update tag string : %s", string); \
725 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
726 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
727 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
728 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
729 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
730 MMPLAYER_FREEIF(new_string); \
732 mm_attrs_set_string_by_name(attribute, playertag, string); \
734 MMPLAYER_FREEIF(string); \
739 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
741 GstSample *sample = NULL;\
742 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
743 GstMapInfo info = GST_MAP_INFO_INIT;\
744 buffer = gst_sample_get_buffer(sample);\
745 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
746 LOGD("failed to get image data from tag");\
747 gst_sample_unref(sample);\
750 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
751 MMPLAYER_FREEIF(player->album_art);\
752 player->album_art = (gchar *)g_malloc(info.size);\
753 if (player->album_art) {\
754 memcpy(player->album_art, info.data, info.size);\
755 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
756 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
757 msg_param.data = (void *)player->album_art;\
758 msg_param.size = info.size;\
759 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
760 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
763 gst_buffer_unmap(buffer, &info);\
764 gst_sample_unref(sample);\
768 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
770 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
773 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
774 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
775 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
776 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
777 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
779 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
780 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
781 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
782 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
783 player->bitrate[track_type] = v_uint; \
784 player->total_bitrate = 0; \
785 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
786 player->total_bitrate += player->bitrate[i]; \
787 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
788 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
789 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
790 player->maximum_bitrate[track_type] = v_uint; \
791 player->total_maximum_bitrate = 0; \
792 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
793 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
794 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
795 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
797 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
804 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
806 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
808 string = g_strdup_printf("%d", g_date_get_year(date));\
809 mm_attrs_set_string_by_name(attribute, playertag, string);\
810 SECURE_LOGD("metainfo year : %s", string);\
811 MMPLAYER_FREEIF(string);\
817 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
820 if (datetime != NULL) {\
821 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
822 mm_attrs_set_string_by_name(attribute, playertag, string);\
823 SECURE_LOGD("metainfo year : %s", string);\
824 MMPLAYER_FREEIF(string);\
825 gst_date_time_unref(datetime);\
830 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
832 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
834 /* FIXIT : don't know how to store date */\
841 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
843 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
845 /* FIXIT : don't know how to store date */\
853 GstTagList *tag_list = NULL;
855 MMHandleType attrs = 0;
860 GstDateTime *datetime = NULL;
862 GstBuffer *buffer = NULL;
864 MMMessageParamType msg_param = {0, };
866 /* currently not used. but those are needed for above macro */
867 //guint64 v_uint64 = 0;
868 //gdouble v_double = 0;
870 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
872 attrs = MMPLAYER_GET_ATTRS(player);
874 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
876 /* get tag list from gst message */
877 gst_message_parse_tag(msg, &tag_list);
879 /* store tags to player attributes */
880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
881 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
882 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
883 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
885 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
887 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
888 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
890 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
891 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
892 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
893 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
894 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
895 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
898 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
900 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
901 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
902 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
904 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
905 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
907 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
908 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
909 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
910 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
911 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
912 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
913 MMPLAYER_UPDATE_TAG_LOCK(player);
914 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
915 MMPLAYER_UPDATE_TAG_UNLOCK(player);
916 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
917 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
918 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
920 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
921 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
922 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
923 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
924 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
925 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
927 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
930 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
931 if (player->video360_metadata.is_spherical == -1) {
932 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
933 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
934 player->video360_metadata.is_spherical);
935 if (player->video360_metadata.is_spherical == 1) {
936 LOGD("This is spherical content for 360 playback.");
937 player->is_content_spherical = TRUE;
939 LOGD("This is not spherical content");
940 player->is_content_spherical = FALSE;
943 if (player->video360_metadata.projection_type_string) {
944 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
945 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
947 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
948 player->is_content_spherical = player->is_video360_enabled = FALSE;
952 if (player->video360_metadata.stereo_mode_string) {
953 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
954 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
955 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
956 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
957 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
958 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
960 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
961 player->is_content_spherical = player->is_video360_enabled = FALSE;
967 if (mm_attrs_commit_all(attrs))
968 LOGE("failed to commit.");
970 gst_tag_list_unref(tag_list);
975 /* if retval is FALSE, it will be dropped for perfomance. */
977 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage *message)
979 gboolean retval = FALSE;
981 if (!(player->pipeline && player->pipeline->mainbin)) {
982 LOGE("player pipeline handle is null");
986 switch (GST_MESSAGE_TYPE(message)) {
987 case GST_MESSAGE_TAG:
988 case GST_MESSAGE_EOS:
989 case GST_MESSAGE_ERROR:
990 case GST_MESSAGE_WARNING:
991 case GST_MESSAGE_CLOCK_LOST:
992 case GST_MESSAGE_NEW_CLOCK:
993 case GST_MESSAGE_ELEMENT:
994 case GST_MESSAGE_DURATION_CHANGED:
995 case GST_MESSAGE_ASYNC_START:
998 case GST_MESSAGE_ASYNC_DONE:
999 case GST_MESSAGE_STATE_CHANGED:
1000 /* we only handle messages from pipeline */
1001 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
1006 case GST_MESSAGE_BUFFERING:
1008 gint buffer_percent = 0;
1011 gst_message_parse_buffering(message, &buffer_percent);
1012 if (buffer_percent != MAX_BUFFER_PERCENT) {
1013 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
1017 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1018 LOGW("can't get cmd lock, send msg to bus");
1022 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1023 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1024 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1027 MMPLAYER_CMD_UNLOCK(player);
1040 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1042 MMHandleType attrs = 0;
1043 guint64 data_size = 0;
1045 gint64 pos_nsec = 0;
1048 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1050 __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1052 attrs = MMPLAYER_GET_ATTRS(player);
1054 LOGE("fail to get attributes.");
1058 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1059 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1060 if (stat(path, &sb) == 0)
1061 data_size = (guint64)sb.st_size;
1062 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1063 data_size = player->http_content_size;
1066 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1067 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1073 __mmplayer_handle_buffering_playback(mm_player_t *player)
1075 int ret = MM_ERROR_NONE;
1076 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1077 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1078 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1079 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1081 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1082 LOGW("do nothing for buffering msg");
1083 ret = MM_ERROR_PLAYER_INVALID_STATE;
1087 prev_state = MMPLAYER_PREV_STATE(player);
1088 current_state = MMPLAYER_CURRENT_STATE(player);
1089 target_state = MMPLAYER_TARGET_STATE(player);
1090 pending_state = MMPLAYER_PENDING_STATE(player);
1092 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1093 MMPLAYER_STATE_GET_NAME(prev_state),
1094 MMPLAYER_STATE_GET_NAME(current_state),
1095 MMPLAYER_STATE_GET_NAME(pending_state),
1096 MMPLAYER_STATE_GET_NAME(target_state),
1097 player->streamer->buffering_state);
1099 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1100 /* NOTE : if buffering has done, player has to go to target state. */
1101 switch (target_state) {
1102 case MM_PLAYER_STATE_PAUSED:
1104 switch (pending_state) {
1105 case MM_PLAYER_STATE_PLAYING:
1106 __mmplayer_gst_pause(player, TRUE);
1109 case MM_PLAYER_STATE_PAUSED:
1110 LOGD("player is already going to paused state, there is nothing to do.");
1113 case MM_PLAYER_STATE_NONE:
1114 case MM_PLAYER_STATE_NULL:
1115 case MM_PLAYER_STATE_READY:
1117 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1123 case MM_PLAYER_STATE_PLAYING:
1125 switch (pending_state) {
1126 case MM_PLAYER_STATE_NONE:
1128 if (current_state != MM_PLAYER_STATE_PLAYING)
1129 __mmplayer_gst_resume(player, TRUE);
1133 case MM_PLAYER_STATE_PAUSED:
1134 /* NOTE: It should be worked as asynchronously.
1135 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1137 if (current_state == MM_PLAYER_STATE_PLAYING) {
1138 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1139 * The current state should be changed to paused purposely to prevent state conflict.
1141 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1143 __mmplayer_gst_resume(player, TRUE);
1146 case MM_PLAYER_STATE_PLAYING:
1147 LOGD("player is already going to playing state, there is nothing to do.");
1150 case MM_PLAYER_STATE_NULL:
1151 case MM_PLAYER_STATE_READY:
1153 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1159 case MM_PLAYER_STATE_NULL:
1160 case MM_PLAYER_STATE_READY:
1161 case MM_PLAYER_STATE_NONE:
1163 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1167 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1168 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1170 switch (pending_state) {
1171 case MM_PLAYER_STATE_NONE:
1173 if (current_state != MM_PLAYER_STATE_PAUSED) {
1174 /* rtsp streaming pause makes rtsp server stop sending data. */
1175 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1176 LOGD("set pause state during buffering");
1177 __mmplayer_gst_pause(player, TRUE);
1183 case MM_PLAYER_STATE_PLAYING:
1184 /* rtsp streaming pause makes rtsp server stop sending data. */
1185 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1186 __mmplayer_gst_pause(player, TRUE);
1189 case MM_PLAYER_STATE_PAUSED:
1192 case MM_PLAYER_STATE_NULL:
1193 case MM_PLAYER_STATE_READY:
1195 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1204 static VariantData *
1205 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1207 VariantData *var_info = NULL;
1208 g_return_val_if_fail(self != NULL, NULL);
1210 var_info = g_new0(VariantData, 1);
1211 if (!var_info) return NULL;
1212 var_info->bandwidth = self->bandwidth;
1213 var_info->width = self->width;
1214 var_info->height = self->height;
1219 __mmplayer_gst_handle_duration(mm_player_t *player, GstMessage *msg)
1225 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1226 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1228 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1229 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1230 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1232 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1233 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1234 player->http_content_size = (bytes > 0) ? bytes : 0;
1237 /* handling audio clip which has vbr. means duration is keep changing */
1238 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1247 __mmplayer_eos_timer_cb(gpointer u_data)
1249 mm_player_t *player = NULL;
1250 MMHandleType attrs = 0;
1253 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1255 player = (mm_player_t *)u_data;
1256 attrs = MMPLAYER_GET_ATTRS(player);
1258 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1262 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1263 if (ret_value != MM_ERROR_NONE)
1264 LOGE("seeking to 0 failed in repeat play");
1267 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1270 /* we are returning FALSE as we need only one posting */
1275 __mmplayer_handle_eos_delay(mm_player_t *player, int delay_in_ms)
1277 MMPLAYER_RETURN_IF_FAIL(player);
1279 /* post now if delay is zero */
1280 if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1281 LOGD("eos delay is zero. posting EOS now");
1282 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1284 if (player->audio_stream_render_cb)
1285 __mmplayer_cancel_eos_timer(player);
1290 /* cancel if existing */
1291 __mmplayer_cancel_eos_timer(player);
1293 /* init new timeout */
1294 /* NOTE : consider give high priority to this timer */
1295 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1297 player->eos_timer = g_timeout_add(delay_in_ms,
1298 __mmplayer_eos_timer_cb, player);
1300 player->context.global_default = g_main_context_default();
1301 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1303 /* check timer is valid. if not, send EOS now */
1304 if (player->eos_timer == 0) {
1305 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1306 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1311 __mmplayer_gst_pending_seek(mm_player_t *player)
1313 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1314 int ret = MM_ERROR_NONE;
1318 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1320 if (!player->pending_seek.is_pending) {
1321 LOGD("pending seek is not reserved. nothing to do.");
1325 /* check player state if player could pending seek or not. */
1326 current_state = MMPLAYER_CURRENT_STATE(player);
1328 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1329 LOGW("try to pending seek in %s state, try next time. ",
1330 MMPLAYER_STATE_GET_NAME(current_state));
1334 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1336 ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1337 if (ret != MM_ERROR_NONE)
1338 LOGE("failed to seek pending postion. just keep staying current position.");
1340 player->pending_seek.is_pending = false;
1348 __mmplayer_gst_set_async(mm_player_t *player, gboolean async, enum MMPlayerSinkType type)
1350 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1352 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1354 audiobin = player->pipeline->audiobin; /* can be null */
1355 videobin = player->pipeline->videobin; /* can be null */
1356 textbin = player->pipeline->textbin; /* can be null */
1358 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1360 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1361 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1363 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1364 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1366 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1367 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1373 __mmplayer_drop_subtitle(mm_player_t *player, gboolean is_drop)
1375 MMPlayerGstElement *textbin;
1378 MMPLAYER_RETURN_IF_FAIL(player &&
1380 player->pipeline->textbin);
1382 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1384 textbin = player->pipeline->textbin;
1387 LOGD("Drop subtitle text after getting EOS");
1389 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1390 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1392 player->is_subtitle_force_drop = TRUE;
1394 if (player->is_subtitle_force_drop == TRUE) {
1395 LOGD("Enable subtitle data path without drop");
1397 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1398 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1400 LOGD("non-connected with external display");
1402 player->is_subtitle_force_drop = FALSE;
1408 __mmplayer_gst_handle_eos_message(mm_player_t *player, GstMessage *msg)
1410 MMHandleType attrs = 0;
1415 /* NOTE : EOS event is comming multiple time. watch out it */
1416 /* check state. we only process EOS when pipeline state goes to PLAYING */
1417 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1418 LOGD("EOS received on non-playing state. ignoring it");
1422 if (player->pipeline && player->pipeline->textbin)
1423 __mmplayer_drop_subtitle(player, TRUE);
1425 if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1426 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1428 /* rewind if repeat count is greater then zero */
1429 /* get play count */
1430 attrs = MMPLAYER_GET_ATTRS(player);
1432 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1434 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1436 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1437 if (player->playback_rate < 0.0) {
1438 player->resumed_by_rewind = TRUE;
1439 _mmplayer_set_mute((MMHandleType)player, 0);
1440 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1443 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1446 player->sent_bos = FALSE;
1448 LOGD("do not post eos msg for repeating");
1453 if (player->pipeline)
1454 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1456 /* post eos message to application */
1457 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1459 /* reset last position */
1460 player->last_position = 0;
1467 __mmplayer_gst_handle_error_message(mm_player_t *player, GstMessage *msg)
1469 GError *error = NULL;
1470 gchar *debug = NULL;
1474 /* generating debug info before returning error */
1475 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1477 /* get error code */
1478 gst_message_parse_error(msg, &error, &debug);
1480 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1481 /* Note : the streaming error from the streaming source is handled
1482 * using __mmplayer_handle_streaming_error.
1484 __mmplayer_handle_streaming_error(player, msg);
1486 /* dump state of all element */
1487 __mmplayer_dump_pipeline_state(player);
1489 /* traslate gst error code to msl error code. then post it
1490 * to application if needed
1492 __mmplayer_handle_gst_error(player, msg, error);
1495 LOGE("error debug : %s", debug);
1498 MMPLAYER_FREEIF(debug);
1499 g_error_free(error);
1506 __mmplayer_gst_handle_buffering_message(mm_player_t *player, GstMessage *msg)
1508 MMMessageParamType msg_param = {0, };
1509 int bRet = MM_ERROR_NONE;
1512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1514 if (!MMPLAYER_IS_STREAMING(player)) {
1515 LOGW("this is not streaming playback.");
1519 MMPLAYER_CMD_LOCK(player);
1521 if (!player->streamer) {
1522 LOGW("Pipeline is shutting down");
1523 MMPLAYER_CMD_UNLOCK(player);
1527 /* ignore the remained buffering message till getting 100% msg */
1528 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1529 gint buffer_percent = 0;
1531 gst_message_parse_buffering(msg, &buffer_percent);
1533 if (buffer_percent == MAX_BUFFER_PERCENT) {
1534 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1535 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1537 MMPLAYER_CMD_UNLOCK(player);
1541 /* ignore the remained buffering message */
1542 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1543 gint buffer_percent = 0;
1545 gst_message_parse_buffering(msg, &buffer_percent);
1547 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1548 player->streamer->buffering_percent, buffer_percent);
1550 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1551 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1552 player->streamer->buffering_req.is_pre_buffering = FALSE;
1554 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1556 LOGD("interrupted buffering - ignored the remained buffering msg!");
1557 MMPLAYER_CMD_UNLOCK(player);
1562 __mmplayer_update_buffer_setting(player, msg);
1564 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1566 if (bRet == MM_ERROR_NONE) {
1567 msg_param.connection.buffering = player->streamer->buffering_percent;
1568 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1570 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1571 player->pending_resume &&
1572 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1574 player->is_external_subtitle_added_now = FALSE;
1575 player->pending_resume = FALSE;
1576 _mmplayer_resume((MMHandleType)player);
1579 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1580 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1582 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1583 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1584 player->seek_state = MMPLAYER_SEEK_NONE;
1585 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1586 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1587 /* Considering the async state trasition in case of RTSP.
1588 After getting state change gst msg, seek cmpleted msg will be posted. */
1589 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1593 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1594 if (!player->streamer) {
1595 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1596 MMPLAYER_CMD_UNLOCK(player);
1600 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1602 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1603 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1605 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1606 msg_param.connection.buffering = player->streamer->buffering_percent;
1607 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1609 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1612 msg_param.connection.buffering = player->streamer->buffering_percent;
1613 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1616 MMPLAYER_CMD_UNLOCK(player);
1624 __mmplayer_gst_handle_state_message(mm_player_t *player, GstMessage *msg)
1626 MMPlayerGstElement *mainbin;
1627 const GValue *voldstate, *vnewstate, *vpending;
1628 GstState oldstate = GST_STATE_NULL;
1629 GstState newstate = GST_STATE_NULL;
1630 GstState pending = GST_STATE_NULL;
1633 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1635 mainbin = player->pipeline->mainbin;
1637 /* we only handle messages from pipeline */
1638 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1641 /* get state info from msg */
1642 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1643 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1644 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1646 if (!voldstate || !vnewstate) {
1647 LOGE("received msg has wrong format.");
1651 oldstate = (GstState)voldstate->data[0].v_int;
1652 newstate = (GstState)vnewstate->data[0].v_int;
1654 pending = (GstState)vpending->data[0].v_int;
1656 LOGD("state changed [%s] : %s ---> %s final : %s",
1657 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1658 gst_element_state_get_name((GstState)oldstate),
1659 gst_element_state_get_name((GstState)newstate),
1660 gst_element_state_get_name((GstState)pending));
1662 if (newstate == GST_STATE_PLAYING) {
1663 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1665 int retVal = MM_ERROR_NONE;
1666 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1668 retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1670 if (MM_ERROR_NONE != retVal)
1671 LOGE("failed to seek pending postion. just keep staying current position.");
1673 player->pending_seek.is_pending = false;
1677 if (oldstate == newstate) {
1678 LOGD("pipeline reports state transition to old state");
1683 case GST_STATE_PAUSED:
1685 gboolean prepare_async = FALSE;
1687 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1688 // managed prepare async case
1689 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1690 LOGD("checking prepare mode for async transition - %d", prepare_async);
1693 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1694 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1696 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1697 __mm_player_streaming_set_content_bitrate(player->streamer,
1698 player->total_maximum_bitrate, player->total_bitrate);
1700 if (player->pending_seek.is_pending) {
1701 LOGW("trying to do pending seek");
1702 MMPLAYER_CMD_LOCK(player);
1703 __mmplayer_gst_pending_seek(player);
1704 MMPLAYER_CMD_UNLOCK(player);
1710 case GST_STATE_PLAYING:
1712 if (MMPLAYER_IS_STREAMING(player)) {
1713 // managed prepare async case when buffering is completed
1714 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1715 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1716 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1717 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1719 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1721 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1722 if (player->streamer->buffering_percent < 100) {
1724 MMMessageParamType msg_param = {0, };
1725 LOGW("Posting Buffering Completed Message to Application !!!");
1727 msg_param.connection.buffering = 100;
1728 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1733 if (player->gapless.stream_changed) {
1734 __mmplayer_update_content_attrs(player, ATTR_ALL);
1735 player->gapless.stream_changed = FALSE;
1738 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1739 player->seek_state = MMPLAYER_SEEK_NONE;
1740 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1744 case GST_STATE_VOID_PENDING:
1745 case GST_STATE_NULL:
1746 case GST_STATE_READY:
1756 __mmplayer_gst_handle_element_message(mm_player_t *player, GstMessage *msg)
1758 const gchar *structure_name;
1759 gint count = 0, idx = 0;
1760 MMHandleType attrs = 0;
1763 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1765 attrs = MMPLAYER_GET_ATTRS(player);
1767 LOGE("Failed to get content attribute");
1771 if (gst_message_get_structure(msg) == NULL)
1774 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1775 if (!structure_name)
1778 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1780 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1781 const GValue *var_info = NULL;
1783 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1784 if (var_info != NULL) {
1785 if (player->adaptive_info.var_list)
1786 g_list_free_full(player->adaptive_info.var_list, g_free);
1788 /* share addr or copy the list */
1789 player->adaptive_info.var_list =
1790 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1792 count = g_list_length(player->adaptive_info.var_list);
1794 VariantData *temp = NULL;
1796 /* print out for debug */
1797 LOGD("num of variant_info %d", count);
1798 for (idx = 0; idx < count; idx++) {
1799 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1801 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1807 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1808 gint num_buffers = 0;
1809 gint extra_num_buffers = 0;
1811 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1812 player->video_num_buffers = num_buffers;
1813 LOGD("video_num_buffers : %d", player->video_num_buffers);
1816 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1817 player->video_extra_num_buffers = extra_num_buffers;
1818 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1823 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1824 __mmplayer_track_update_text_attr_info(player, msg);
1826 /* custom message */
1827 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1828 MMMessageParamType msg_param = {0,};
1829 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1830 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1833 /* custom message for RTSP attribute :
1834 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1835 sdp which has contents info is received when rtsp connection is opened.
1836 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1837 if (!strcmp(structure_name, "rtspsrc_properties")) {
1838 gchar *audio_codec = NULL;
1839 gchar *video_codec = NULL;
1840 gchar *video_frame_size = NULL;
1842 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1843 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1844 player->streaming_type = __mmplayer_get_stream_service_type(player);
1846 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1847 LOGD("rtsp_audio_codec : %s", audio_codec);
1849 mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1851 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1852 LOGD("rtsp_video_codec : %s", video_codec);
1854 mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1856 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1857 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1858 if (video_frame_size) {
1859 char *seperator = strchr(video_frame_size, '-');
1861 char video_width[10] = {0,};
1862 int frame_size_len = strlen(video_frame_size);
1863 int separtor_len = strlen(seperator);
1865 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1866 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1869 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1873 if (mm_attrs_commit_all(attrs))
1874 LOGE("failed to commit.");
1882 __mmplayer_gst_handle_async_done_message(mm_player_t *player, GstMessage *msg)
1884 MMPlayerGstElement *mainbin;
1887 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1889 mainbin = player->pipeline->mainbin;
1891 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1893 /* we only handle messages from pipeline */
1894 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1897 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1898 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1899 player->seek_state = MMPLAYER_SEEK_NONE;
1900 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1901 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1902 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1903 LOGD("sync %s state(%s) with parent state(%s)",
1904 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1905 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1906 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1908 /* In case of streaming, pause is required before finishing seeking by buffering.
1909 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1910 Because the buffering state is controlled according to the state transition for force resume,
1911 the decodebin state should be paused as player state. */
1912 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1915 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1916 (player->streamer) &&
1917 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1918 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1919 GstQuery *query = NULL;
1920 gboolean busy = FALSE;
1923 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1924 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1925 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1926 gst_query_parse_buffering_percent(query, &busy, &percent);
1927 gst_query_unref(query);
1929 LOGD("buffered percent(%s): %d",
1930 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1934 __mmplayer_handle_buffering_playback(player);
1937 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1946 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1948 mm_player_t *player = (mm_player_t *)(data);
1950 MMPLAYER_RETURN_IF_FAIL(player);
1951 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1953 switch (GST_MESSAGE_TYPE(msg)) {
1954 case GST_MESSAGE_UNKNOWN:
1955 LOGD("unknown message received");
1958 case GST_MESSAGE_EOS:
1959 LOGD("GST_MESSAGE_EOS received");
1960 __mmplayer_gst_handle_eos_message(player, msg);
1963 case GST_MESSAGE_ERROR:
1964 __mmplayer_gst_handle_error_message(player, msg);
1967 case GST_MESSAGE_WARNING:
1970 GError *error = NULL;
1972 gst_message_parse_warning(msg, &error, &debug);
1974 LOGD("warning : %s", error->message);
1975 LOGD("debug : %s", debug);
1977 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1979 MMPLAYER_FREEIF(debug);
1980 g_error_free(error);
1984 case GST_MESSAGE_TAG:
1986 LOGD("GST_MESSAGE_TAG");
1987 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1988 LOGW("failed to extract tags from gstmessage");
1992 case GST_MESSAGE_BUFFERING:
1993 __mmplayer_gst_handle_buffering_message(player, msg);
1996 case GST_MESSAGE_STATE_CHANGED:
1997 __mmplayer_gst_handle_state_message(player, msg);
2000 case GST_MESSAGE_CLOCK_LOST:
2002 GstClock *clock = NULL;
2003 gboolean need_new_clock = FALSE;
2005 gst_message_parse_clock_lost(msg, &clock);
2006 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2008 if (!player->videodec_linked)
2009 need_new_clock = TRUE;
2010 else if (!player->ini.use_system_clock)
2011 need_new_clock = TRUE;
2013 if (need_new_clock) {
2014 LOGD("Provide clock is TRUE, do pause->resume");
2015 __mmplayer_gst_pause(player, FALSE);
2016 __mmplayer_gst_resume(player, FALSE);
2021 case GST_MESSAGE_NEW_CLOCK:
2023 GstClock *clock = NULL;
2024 gst_message_parse_new_clock(msg, &clock);
2025 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2029 case GST_MESSAGE_ELEMENT:
2030 __mmplayer_gst_handle_element_message(player, msg);
2033 case GST_MESSAGE_DURATION_CHANGED:
2035 LOGD("GST_MESSAGE_DURATION_CHANGED");
2036 if (!__mmplayer_gst_handle_duration(player, msg))
2037 LOGW("failed to update duration");
2041 case GST_MESSAGE_ASYNC_START:
2042 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2045 case GST_MESSAGE_ASYNC_DONE:
2046 __mmplayer_gst_handle_async_done_message(player, msg);
2049 #if 0 /* delete unnecessary logs */
2050 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2051 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2052 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2053 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2054 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2055 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2056 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2057 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2058 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2059 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2060 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2061 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2062 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2063 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2064 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2071 /* should not call 'gst_message_unref(msg)' */
2075 static GstBusSyncReply
2076 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2078 mm_player_t *player = (mm_player_t *)data;
2079 GstBusSyncReply reply = GST_BUS_DROP;
2081 if (!(player->pipeline && player->pipeline->mainbin)) {
2082 LOGE("player pipeline handle is null");
2083 return GST_BUS_PASS;
2086 if (!__mmplayer_gst_check_useful_message(player, message)) {
2087 gst_message_unref(message);
2088 return GST_BUS_DROP;
2091 switch (GST_MESSAGE_TYPE(message)) {
2092 case GST_MESSAGE_TAG:
2093 __mmplayer_gst_extract_tag_from_msg(player, message);
2097 GstTagList *tags = NULL;
2099 gst_message_parse_tag(message, &tags);
2101 LOGE("TAGS received from element \"%s\".",
2102 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2104 gst_tag_list_foreach(tags, print_tag, NULL);
2105 gst_tag_list_unref(tags);
2113 case GST_MESSAGE_DURATION_CHANGED:
2114 __mmplayer_gst_handle_duration(player, message);
2116 case GST_MESSAGE_ASYNC_DONE:
2117 /* NOTE:Don't call gst_callback directly
2118 * because previous frame can be showed even though this message is received for seek.
2121 reply = GST_BUS_PASS;
2125 if (reply == GST_BUS_DROP)
2126 gst_message_unref(message);
2132 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2134 GstElement *appsrc = element;
2135 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2136 GstBuffer *buffer = NULL;
2137 GstFlowReturn ret = GST_FLOW_OK;
2140 MMPLAYER_RETURN_IF_FAIL(element);
2141 MMPLAYER_RETURN_IF_FAIL(buf);
2143 buffer = gst_buffer_new();
2145 if (buf->offset < 0 || buf->len < 0) {
2146 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2150 if (buf->offset >= buf->len) {
2151 LOGD("call eos appsrc");
2152 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2156 if (buf->len - buf->offset < size)
2157 len = buf->len - buf->offset;
2159 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2160 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2161 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2163 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2164 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2170 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2172 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2174 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2176 buf->offset = (int)size;
2182 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2184 mm_player_t *player = (mm_player_t *)user_data;
2185 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2186 guint64 current_level_bytes = 0;
2188 MMPLAYER_RETURN_IF_FAIL(player);
2190 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2191 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2192 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2193 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2194 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2195 type = MM_PLAYER_STREAM_TYPE_TEXT;
2197 LOGE("can not enter here");
2201 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2203 LOGI("type: %d, level: %"G_GUINT64_FORMAT, type, current_level_bytes);
2205 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2206 if (player->media_stream_buffer_status_cb[type])
2207 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2208 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2212 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2214 mm_player_t *player = (mm_player_t *)user_data;
2215 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2216 guint64 current_level_bytes = 0;
2218 MMPLAYER_RETURN_IF_FAIL(player);
2220 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2221 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2222 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2223 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2224 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2225 type = MM_PLAYER_STREAM_TYPE_TEXT;
2227 LOGE("can not enter here");
2231 LOGI("type: %d, buffer is full", type);
2233 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2235 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2237 if (player->media_stream_buffer_status_cb[type])
2238 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2240 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2244 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2246 mm_player_t *player = (mm_player_t *)user_data;
2247 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2249 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2251 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2252 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2253 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2254 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2255 } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2256 type = MM_PLAYER_STREAM_TYPE_TEXT;
2258 LOGE("can not enter here");
2262 LOGD("type: %d, pos: %"G_GUINT64_FORMAT, type, position);
2263 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2265 if (player->media_stream_seek_data_cb[type])
2266 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2267 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2273 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad *srcpad)
2275 #define MAX_LEN_NAME 20
2277 gboolean ret = FALSE;
2278 GstPad *sinkpad = NULL;
2279 gchar *prefix = NULL;
2280 gchar dec_name[MAX_LEN_NAME] = {0, };
2281 enum MainElementID elem_id = MMPLAYER_M_NUM;
2283 MMPlayerGstElement *mainbin = NULL;
2284 GstElement *decodebin = NULL;
2285 GstCaps *dec_caps = NULL;
2289 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2291 player->pipeline->mainbin, FALSE);
2292 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2294 mainbin = player->pipeline->mainbin;
2296 case MM_PLAYER_STREAM_TYPE_AUDIO:
2298 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2300 case MM_PLAYER_STREAM_TYPE_VIDEO:
2302 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2305 LOGE("invalid type %d", type);
2309 if (mainbin[elem_id].gst) {
2310 LOGE("elem(%d) is already created", elem_id);
2314 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2316 /* create decodebin */
2317 decodebin = gst_element_factory_make("decodebin", dec_name);
2319 LOGE("failed to create %s", dec_name);
2323 mainbin[elem_id].id = elem_id;
2324 mainbin[elem_id].gst = decodebin;
2326 /* raw pad handling signal */
2327 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2328 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2330 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2331 before looking for any elements that can handle that stream.*/
2332 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2333 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2335 /* This signal is emitted when a element is added to the bin.*/
2336 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2337 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2339 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2340 LOGE("failed to add new decodebin");
2344 dec_caps = gst_pad_query_caps(srcpad, NULL);
2346 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2347 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2348 gst_caps_unref(dec_caps);
2351 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2353 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2354 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2357 gst_object_unref(GST_OBJECT(sinkpad));
2359 gst_element_sync_state_with_parent(decodebin);
2365 gst_object_unref(GST_OBJECT(sinkpad));
2367 if (mainbin[elem_id].gst) {
2368 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2369 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2370 gst_object_unref(mainbin[elem_id].gst);
2371 mainbin[elem_id].gst = NULL;
2379 __mmplayer_gst_create_es_path(mm_player_t *player, MMPlayerStreamType type, GstCaps *caps)
2381 #define MAX_LEN_NAME 20
2382 MMPlayerGstElement *mainbin = NULL;
2383 gchar *prefix = NULL;
2384 enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2386 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2387 GstElement *src = NULL, *queue = NULL;
2388 GstPad *srcpad = NULL;
2391 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2392 player->pipeline->mainbin, FALSE);
2394 mainbin = player->pipeline->mainbin;
2396 LOGD("type(%d) path is creating", type);
2398 case MM_PLAYER_STREAM_TYPE_AUDIO:
2400 if (mainbin[MMPLAYER_M_SRC].gst)
2401 src_id = MMPLAYER_M_2ND_SRC;
2403 src_id = MMPLAYER_M_SRC;
2404 queue_id = MMPLAYER_M_A_BUFFER;
2406 case MM_PLAYER_STREAM_TYPE_VIDEO:
2408 src_id = MMPLAYER_M_SRC;
2409 queue_id = MMPLAYER_M_V_BUFFER;
2411 case MM_PLAYER_STREAM_TYPE_TEXT:
2412 prefix = "subtitle";
2413 src_id = MMPLAYER_M_SUBSRC;
2414 queue_id = MMPLAYER_M_S_BUFFER;
2417 LOGE("invalid type %d", type);
2421 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2422 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2425 src = gst_element_factory_make("appsrc", src_name);
2427 LOGF("failed to create %s", src_name);
2431 mainbin[src_id].id = src_id;
2432 mainbin[src_id].gst = src;
2434 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2435 "caps", caps, NULL);
2437 /* size of many video frames are larger than default blocksize as 4096 */
2438 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2439 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2441 if (player->media_stream_buffer_max_size[type] > 0)
2442 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2444 if (player->media_stream_buffer_min_percent[type] > 0)
2445 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2447 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2448 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2450 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2451 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2452 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2453 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2454 __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2455 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2458 queue = gst_element_factory_make("queue2", queue_name);
2460 LOGE("failed to create %s", queue_name);
2463 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2465 mainbin[queue_id].id = queue_id;
2466 mainbin[queue_id].gst = queue;
2468 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2469 LOGE("failed to add src");
2473 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2474 LOGE("failed to add queue");
2478 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2479 LOGE("failed to link src and queue");
2483 /* create decoder */
2484 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2486 LOGE("failed to get srcpad of queue");
2490 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2491 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2493 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2494 LOGE("failed to create decoder");
2495 gst_object_unref(GST_OBJECT(srcpad));
2499 gst_object_unref(GST_OBJECT(srcpad));
2503 if (mainbin[src_id].gst) {
2504 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2505 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2506 gst_object_unref(mainbin[src_id].gst);
2507 mainbin[src_id].gst = NULL;
2510 if (mainbin[queue_id].gst) {
2511 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2512 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2513 gst_object_unref(mainbin[queue_id].gst);
2514 mainbin[queue_id].gst = NULL;
2521 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2523 GstPad *sinkpad = NULL;
2524 GstCaps *caps = NULL;
2525 GstElement *new_element = NULL;
2526 GstStructure *str = NULL;
2527 const gchar *name = NULL;
2529 mm_player_t *player = (mm_player_t *)data;
2533 MMPLAYER_RETURN_IF_FAIL(element && pad);
2534 MMPLAYER_RETURN_IF_FAIL(player &&
2536 player->pipeline->mainbin);
2538 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2539 * num_dynamic_pad will decreased after creating a sinkbin.
2541 player->num_dynamic_pad++;
2542 LOGD("stream count inc : %d", player->num_dynamic_pad);
2544 caps = gst_pad_query_caps(pad, NULL);
2545 MMPLAYER_CHECK_NULL(caps);
2547 str = gst_caps_get_structure (caps, 0);
2548 name = gst_structure_get_string(str, "media");
2550 LOGE("cannot get mimetype from structure.");
2554 if (strstr(name, "video")) {
2556 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2558 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2559 if (player->v_stream_caps) {
2560 gst_caps_unref(player->v_stream_caps);
2561 player->v_stream_caps = NULL;
2564 new_element = gst_element_factory_make("fakesink", NULL);
2565 player->num_dynamic_pad--;
2570 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2571 LOGE("failed to autoplug for caps");
2575 gst_caps_unref(caps);
2580 /* excute new_element if created*/
2582 LOGD("adding new element to pipeline");
2584 /* set state to READY before add to bin */
2585 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2587 /* add new element to the pipeline */
2588 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2589 LOGE("failed to add autoplug element to bin");
2593 /* get pad from element */
2594 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2596 LOGE("failed to get sinkpad from autoplug element");
2601 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2602 LOGE("failed to link autoplug element");
2606 gst_object_unref(sinkpad);
2609 /* run. setting PLAYING here since streamming source is live source */
2610 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2614 gst_caps_unref(caps);
2620 STATE_CHANGE_FAILED:
2622 /* FIXIT : take care if new_element has already added to pipeline */
2624 gst_object_unref(GST_OBJECT(new_element));
2627 gst_object_unref(GST_OBJECT(sinkpad));
2630 gst_caps_unref(caps);
2632 /* FIXIT : how to inform this error to MSL ????? */
2633 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2634 * then post an error to application
2639 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2641 mm_player_t *player = (mm_player_t *)data;
2645 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2646 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2647 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2648 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2650 * [1] audio and video will be dumped with filesink.
2651 * [2] autoplugging is done by just using pad caps.
2652 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2653 * and the video will be dumped via filesink.
2655 if (player->num_dynamic_pad == 0) {
2656 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2658 if (!__mmplayer_gst_remove_fakesink(player,
2659 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2660 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2661 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2662 * source element are not same. To overcome this situation, this function will called
2663 * several places and several times. Therefore, this is not an error case.
2668 /* create dot before error-return. for debugging */
2669 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2671 player->no_more_pad = TRUE;
2677 __mmplayer_gst_make_rtsp_src(mm_player_t *player)
2679 GstElement *element = NULL;
2680 gchar *user_agent = NULL;
2681 MMHandleType attrs = 0;
2684 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2686 /* get profile attribute */
2687 attrs = MMPLAYER_GET_ATTRS(player);
2689 LOGE("failed to get content attribute");
2693 element = gst_element_factory_make("rtspsrc", "rtsp source");
2695 LOGE("failed to create rtspsrc element");
2700 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2702 SECURE_LOGD("user_agent : %s", user_agent);
2704 /* setting property to streaming source */
2705 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2707 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2709 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2710 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2711 __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2712 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2719 __mmplayer_gst_make_http_src(mm_player_t *player)
2721 GstElement *element = NULL;
2722 MMHandleType attrs = 0;
2723 gchar *user_agent, *cookies, **cookie_list;
2724 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2725 user_agent = cookies = NULL;
2729 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2731 /* get profile attribute */
2732 attrs = MMPLAYER_GET_ATTRS(player);
2734 LOGE("failed to get content attribute");
2738 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2740 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2742 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2747 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2748 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2750 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2751 http_timeout = player->ini.http_timeout;
2754 SECURE_LOGD("location : %s", player->profile.uri);
2755 SECURE_LOGD("cookies : %s", cookies);
2756 SECURE_LOGD("user_agent : %s", user_agent);
2757 LOGD("timeout : %d", http_timeout);
2759 /* setting property to streaming source */
2760 g_object_set(G_OBJECT(element), "location", player->profile.uri,
2761 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), NULL);
2763 /* parsing cookies */
2764 if ((cookie_list = util_get_cookie_list((const char *)cookies))) {
2765 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2766 g_strfreev(cookie_list);
2770 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2772 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2773 LOGW("[DASH] this is still experimental feature");
2780 __mmplayer_gst_make_file_src(mm_player_t *player)
2782 GstElement *element = NULL;
2785 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2787 LOGD("using filesrc for 'file://' handler");
2788 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2789 LOGE("failed to get storage info");
2793 element = gst_element_factory_make("filesrc", "source");
2795 LOGE("failed to create filesrc");
2799 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2806 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2808 mm_player_t *player = (mm_player_t *)data;
2810 g_return_val_if_fail(player, FALSE);
2811 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2813 gst_message_ref(msg);
2815 g_mutex_lock(&player->bus_msg_q_lock);
2816 g_queue_push_tail(player->bus_msg_q, msg);
2817 g_mutex_unlock(&player->bus_msg_q_lock);
2819 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2820 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2821 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2825 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2827 mm_player_t *player = (mm_player_t *)(data);
2828 GstMessage *msg = NULL;
2832 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2834 player->pipeline->mainbin &&
2835 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2838 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2840 LOGE("cannot get BUS from the pipeline");
2844 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2846 LOGD("[handle: %p] gst bus msg thread will be started.", player);
2847 while (!player->bus_msg_thread_exit) {
2848 g_mutex_lock(&player->bus_msg_q_lock);
2849 msg = g_queue_pop_head(player->bus_msg_q);
2850 g_mutex_unlock(&player->bus_msg_q_lock);
2852 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2855 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2856 /* handle the gst msg */
2857 __mmplayer_gst_bus_msg_callback(msg, player);
2858 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2859 gst_message_unref(msg);
2862 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2863 gst_object_unref(GST_OBJECT(bus));
2870 __mmplayer_gst_check_duration(mm_player_t *player, gint64 position)
2872 gint64 dur_nsec = 0;
2875 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2877 if (MMPLAYER_IS_MS_BUFF_SRC(player))
2878 return MM_ERROR_NONE;
2880 /* NOTE : duration cannot be zero except live streaming.
2881 * Since some element could have some timing problemn with quering duration, try again.
2883 if (player->duration == 0) {
2884 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2885 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2886 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2887 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2888 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2889 player->pending_seek.is_pending = true;
2890 player->pending_seek.pos = position;
2891 player->seek_state = MMPLAYER_SEEK_NONE;
2892 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2893 return MM_ERROR_PLAYER_NO_OP;
2895 player->seek_state = MMPLAYER_SEEK_NONE;
2896 return MM_ERROR_PLAYER_SEEK;
2899 player->duration = dur_nsec;
2902 if (player->duration > 0 && player->duration < position) {
2903 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2904 return MM_ERROR_INVALID_ARGUMENT;
2908 return MM_ERROR_NONE;
2912 __mmplayer_gst_check_seekable(mm_player_t *player)
2914 GstQuery *query = NULL;
2915 gboolean seekable = FALSE;
2917 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2921 query = gst_query_new_seeking(GST_FORMAT_TIME);
2922 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2923 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2924 gst_query_unref(query);
2927 LOGW("non-seekable content");
2928 player->seek_state = MMPLAYER_SEEK_NONE;
2932 LOGW("failed to get seeking query");
2933 gst_query_unref(query); /* keep seeking operation */
2940 __mmplayer_gst_set_state(mm_player_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
2942 GstState element_state = GST_STATE_VOID_PENDING;
2943 GstState element_pending_state = GST_STATE_VOID_PENDING;
2944 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2948 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2949 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2951 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2954 ret = gst_element_set_state(element, state);
2955 if (ret == GST_STATE_CHANGE_FAILURE) {
2956 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2958 /* dump state of all element */
2959 __mmplayer_dump_pipeline_state(player);
2961 return MM_ERROR_PLAYER_INTERNAL;
2964 /* return here so state transition to be done in async mode */
2966 LOGD("async state transition. not waiting for state complete.");
2967 return MM_ERROR_NONE;
2970 /* wait for state transition */
2971 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2972 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2973 LOGE("failed to change [%s] element state to [%s] within %d sec",
2974 GST_ELEMENT_NAME(element),
2975 gst_element_state_get_name(state), timeout);
2977 LOGE(" [%s] state : %s pending : %s",
2978 GST_ELEMENT_NAME(element),
2979 gst_element_state_get_name(element_state),
2980 gst_element_state_get_name(element_pending_state));
2982 /* dump state of all element */
2983 __mmplayer_dump_pipeline_state(player);
2985 return MM_ERROR_PLAYER_INTERNAL;
2988 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2992 return MM_ERROR_NONE;
2996 __mmplayer_gst_start(mm_player_t *player)
2998 int ret = MM_ERROR_NONE;
2999 gboolean async = FALSE;
3003 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3005 /* NOTE : if SetPosition was called before Start. do it now
3006 * streaming doesn't support it. so it should be always sync
3007 * !!create one more api to check if there is pending seek rather than checking variables
3009 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3010 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3011 ret = __mmplayer_gst_pause(player, FALSE);
3012 if (ret != MM_ERROR_NONE) {
3013 LOGE("failed to set state to PAUSED for pending seek");
3017 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3018 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3019 LOGW("failed to seek pending postion. starting from the begin of content");
3022 LOGD("current state before doing transition");
3023 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3024 MMPLAYER_PRINT_STATE(player);
3026 /* set pipeline state to PLAYING */
3027 ret = __mmplayer_gst_set_state(player,
3028 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3029 if (ret != MM_ERROR_NONE) {
3030 LOGE("failed to set state to PLAYING");
3034 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3036 /* generating debug info before returning error */
3037 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3045 __mmplayer_gst_stop(mm_player_t *player)
3047 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3048 MMHandleType attrs = 0;
3049 gboolean rewind = FALSE;
3051 int ret = MM_ERROR_NONE;
3055 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3056 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3058 LOGD("current state before doing transition");
3059 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3060 MMPLAYER_PRINT_STATE(player);
3062 attrs = MMPLAYER_GET_ATTRS(player);
3064 LOGE("cannot get content attribute");
3065 return MM_ERROR_PLAYER_INTERNAL;
3068 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3069 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3071 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3072 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3075 if (player->es_player_push_mode)
3076 /* disable the async state transition because there could be no data in the pipeline */
3077 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3080 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3082 if (player->es_player_push_mode) {
3083 /* enable the async state transition as default operation */
3084 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3087 /* return if set_state has failed */
3088 if (ret != MM_ERROR_NONE) {
3089 LOGE("failed to set state.");
3095 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3096 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3097 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3098 LOGW("failed to rewind");
3099 ret = MM_ERROR_PLAYER_SEEK;
3104 player->sent_bos = FALSE;
3106 if (player->es_player_push_mode) //for cloudgame
3109 /* wait for seek to complete */
3110 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3111 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3112 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3114 LOGE("fail to stop player.");
3115 ret = MM_ERROR_PLAYER_INTERNAL;
3116 __mmplayer_dump_pipeline_state(player);
3119 /* generate dot file if enabled */
3120 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3128 __mmplayer_gst_pause(mm_player_t *player, gboolean async)
3130 int ret = MM_ERROR_NONE;
3134 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3135 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3137 LOGD("current state before doing transition");
3138 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3139 MMPLAYER_PRINT_STATE(player);
3141 /* set pipeline status to PAUSED */
3142 ret = __mmplayer_gst_set_state(player,
3143 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3148 if (ret != MM_ERROR_NONE) {
3149 GstMessage *msg = NULL;
3150 GTimer *timer = NULL;
3151 gdouble MAX_TIMEOUT_SEC = 3;
3153 LOGE("failed to set state to PAUSED");
3155 if (!player->bus_watcher) {
3156 LOGE("there is no bus msg thread. pipeline is shutting down.");
3160 if (player->msg_posted) {
3161 LOGE("error msg is already posted.");
3165 timer = g_timer_new();
3166 g_timer_start(timer);
3168 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3171 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3173 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3174 GError *error = NULL;
3176 /* parse error code */
3177 gst_message_parse_error(msg, &error, NULL);
3179 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3180 /* Note : the streaming error from the streaming source is handled
3181 * using __mmplayer_handle_streaming_error.
3183 __mmplayer_handle_streaming_error(player, msg);
3186 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3188 if (error->domain == GST_STREAM_ERROR)
3189 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3190 else if (error->domain == GST_RESOURCE_ERROR)
3191 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3192 else if (error->domain == GST_LIBRARY_ERROR)
3193 ret = __mmplayer_gst_handle_library_error(player, error->code);
3194 else if (error->domain == GST_CORE_ERROR)
3195 ret = __mmplayer_gst_handle_core_error(player, error->code);
3197 g_error_free(error);
3199 player->msg_posted = TRUE;
3201 gst_message_unref(msg);
3203 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3205 gst_object_unref(bus);
3206 g_timer_stop(timer);
3207 g_timer_destroy(timer);
3212 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3213 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3214 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3216 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3219 /* generate dot file before returning error */
3220 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3228 __mmplayer_gst_resume(mm_player_t *player, gboolean async)
3230 int ret = MM_ERROR_NONE;
3235 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3236 MM_ERROR_PLAYER_NOT_INITIALIZED);
3238 LOGD("current state before doing transition");
3239 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3240 MMPLAYER_PRINT_STATE(player);
3243 LOGD("do async state transition to PLAYING");
3245 /* set pipeline state to PLAYING */
3246 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3248 ret = __mmplayer_gst_set_state(player,
3249 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3250 if (ret != MM_ERROR_NONE) {
3251 LOGE("failed to set state to PLAYING");
3256 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3259 /* generate dot file */
3260 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3267 /* sending event to one of sinkelements */
3269 __mmplayer_gst_send_event_to_sink(mm_player_t *player, GstEvent *event)
3271 GstEvent *event2 = NULL;
3272 GList *sinks = NULL;
3273 gboolean res = FALSE;
3276 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3277 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3279 /* While adding subtitles in live feeds seek is getting called.
3280 Adding defensive check in framework layer.*/
3281 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3282 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3283 LOGE("Should not send seek event during live playback");
3288 if (player->play_subtitle)
3289 event2 = gst_event_copy((const GstEvent *)event);
3291 sinks = player->sink_elements;
3293 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3295 if (GST_IS_ELEMENT(sink)) {
3296 /* keep ref to the event */
3297 gst_event_ref(event);
3299 if ((res = gst_element_send_event(sink, event))) {
3300 LOGD("sending event[%s] to sink element [%s] success!",
3301 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3303 /* rtsp case, asyn_done is not called after seek during pause state */
3304 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3305 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3306 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3307 LOGD("RTSP seek completed, after pause state..");
3308 player->seek_state = MMPLAYER_SEEK_NONE;
3309 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3315 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3316 sinks = g_list_next(sinks);
3323 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3324 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3327 sinks = g_list_next(sinks);
3330 /* Note : Textbin is not linked to the video or audio bin.
3331 * It needs to send the event to the text sink seperatelly.
3333 if (player->play_subtitle && player->pipeline) {
3334 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3336 if (GST_IS_ELEMENT(text_sink)) {
3337 /* keep ref to the event */
3338 gst_event_ref(event2);
3340 if ((res = gst_element_send_event(text_sink, event2)))
3341 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3342 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3344 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3345 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3347 gst_event_unref(event2);
3351 gst_event_unref(event);
3359 __mmplayer_gst_seek(mm_player_t *player, GstElement *element, gdouble rate,
3360 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3361 gint64 cur, GstSeekType stop_type, gint64 stop)
3363 GstEvent *event = NULL;
3364 gboolean result = FALSE;
3368 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3370 if (player->pipeline && player->pipeline->textbin)
3371 __mmplayer_drop_subtitle(player, FALSE);
3373 event = gst_event_new_seek(rate, format, flags, cur_type,
3374 cur, stop_type, stop);
3376 result = __mmplayer_gst_send_event_to_sink(player, event);
3384 __mmplayer_gst_set_position(mm_player_t *player, gint64 position, gboolean internal_called)
3386 int ret = MM_ERROR_NONE;
3387 gint64 pos_nsec = 0;
3388 gboolean accurated = FALSE;
3389 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3392 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3393 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3395 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3396 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3399 ret = __mmplayer_gst_check_duration(player, position);
3400 if (ret != MM_ERROR_NONE) {
3401 LOGE("failed to check duration 0x%X", ret);
3402 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3405 if (!__mmplayer_gst_check_seekable(player))
3406 return MM_ERROR_PLAYER_NO_OP;
3408 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3409 position, player->playback_rate, player->duration);
3411 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3412 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3413 This causes problem is position calculation during normal pause resume scenarios also.
3414 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3415 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3416 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3417 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3418 LOGW("getting current position failed in seek");
3420 player->last_position = pos_nsec;
3421 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3424 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3425 LOGD("not completed seek");
3426 return MM_ERROR_PLAYER_DOING_SEEK;
3429 if (!internal_called)
3430 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3432 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3433 that's why set position through property. */
3434 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3435 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3436 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3437 (!player->videodec_linked) && (!player->audiodec_linked)) {
3439 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3440 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3442 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3443 player->seek_state = MMPLAYER_SEEK_NONE;
3444 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3446 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3448 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3450 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3452 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3453 GST_FORMAT_TIME, seek_flags,
3454 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3455 LOGE("failed to set position");
3460 /* NOTE : store last seeking point to overcome some bad operation
3461 * (returning zero when getting current position) of some elements
3463 player->last_position = position;
3465 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3466 if (player->playback_rate > 1.0)
3467 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3469 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3470 LOGD("buffering should be reset after seeking");
3471 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3472 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3476 return MM_ERROR_NONE;
3479 player->pending_seek.is_pending = true;
3480 player->pending_seek.pos = position;
3482 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3483 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3484 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3485 player->pending_seek.pos);
3487 return MM_ERROR_NONE;
3490 player->seek_state = MMPLAYER_SEEK_NONE;
3491 return MM_ERROR_PLAYER_SEEK;
3495 __mmplayer_gst_get_position(mm_player_t *player, gint64 *position)
3497 #define TRICKPLAY_OFFSET GST_MSECOND
3499 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3500 gint64 pos_nsec = 0;
3501 gboolean ret = TRUE;
3503 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3504 MM_ERROR_PLAYER_NOT_INITIALIZED);
3506 current_state = MMPLAYER_CURRENT_STATE(player);
3508 /* NOTE : query position except paused state to overcome some bad operation
3509 * please refer to below comments in details
3511 if (current_state != MM_PLAYER_STATE_PAUSED)
3512 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3514 /* NOTE : get last point to overcome some bad operation of some elements
3515 *(returning zero when getting current position in paused state
3516 * and when failed to get postion during seeking
3518 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3519 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3521 if (player->playback_rate < 0.0)
3522 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3524 pos_nsec = player->last_position;
3527 pos_nsec = player->last_position;
3529 player->last_position = pos_nsec;
3531 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3534 if (player->duration > 0 && pos_nsec > player->duration)
3535 pos_nsec = player->duration;
3537 player->last_position = pos_nsec;
3540 *position = pos_nsec;
3542 return MM_ERROR_NONE;
3546 __mmplayer_gst_get_buffer_position(mm_player_t *player, int *start_pos, int *end_pos)
3548 #define STREAMING_IS_FINISHED 0
3549 #define BUFFERING_MAX_PER 100
3550 #define DEFAULT_PER_VALUE -1
3551 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3553 MMPlayerGstElement *mainbin = NULL;
3554 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3555 gint64 buffered_total = 0;
3556 gint64 position = 0;
3557 gint buffered_sec = -1;
3558 GstBufferingMode mode = GST_BUFFERING_STREAM;
3559 gint64 content_size_time = player->duration;
3560 guint64 content_size_bytes = player->http_content_size;
3562 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3564 player->pipeline->mainbin,
3565 MM_ERROR_PLAYER_NOT_INITIALIZED);
3567 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3572 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3573 /* and rtsp is not ready yet. */
3574 LOGW("it's only used for http streaming case");
3575 return MM_ERROR_PLAYER_NO_OP;
3578 if (content_size_time <= 0 || content_size_bytes <= 0) {
3579 LOGW("there is no content size");
3580 return MM_ERROR_NONE;
3583 if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3584 LOGW("fail to get current position");
3585 return MM_ERROR_NONE;
3588 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3589 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3591 mainbin = player->pipeline->mainbin;
3592 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3594 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3595 GstQuery *query = NULL;
3596 gint byte_in_rate = 0, byte_out_rate = 0;
3597 gint64 estimated_total = 0;
3599 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3600 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3601 LOGW("fail to get buffering query from queue2");
3603 gst_query_unref(query);
3604 return MM_ERROR_NONE;
3607 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3608 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3610 if (mode == GST_BUFFERING_STREAM) {
3611 /* using only queue in case of push mode(ts / mp3) */
3612 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3613 GST_FORMAT_BYTES, &buffered_total)) {
3614 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3615 end_per = 100 * buffered_total / content_size_bytes;
3618 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3620 guint num_of_ranges = 0;
3621 gint64 start_byte = 0, stop_byte = 0;
3623 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3624 if (estimated_total != STREAMING_IS_FINISHED) {
3625 /* buffered size info from queue2 */
3626 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3627 for (idx = 0; idx < num_of_ranges; idx++) {
3628 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3629 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3631 buffered_total += (stop_byte - start_byte);
3634 end_per = BUFFERING_MAX_PER;
3637 gst_query_unref(query);
3640 if (end_per == DEFAULT_PER_VALUE) {
3641 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3643 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3645 /* buffered size info from multiqueue */
3646 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3647 guint curr_size_bytes = 0;
3648 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3649 "curr-size-bytes", &curr_size_bytes, NULL);
3650 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3651 buffered_total += curr_size_bytes;
3654 if (avg_byterate > 0)
3655 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3656 else if (player->total_maximum_bitrate > 0)
3657 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3658 else if (player->total_bitrate > 0)
3659 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3661 if (buffered_sec >= 0)
3662 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3666 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3667 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3669 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3670 buffered_total, buffered_sec, *start_pos, *end_pos);
3672 return MM_ERROR_NONE;
3676 __mmplayer_gst_create_source(mm_player_t *player)
3678 GstElement *element = NULL;
3681 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3682 player->pipeline->mainbin, NULL);
3684 /* setup source for gapless play */
3685 switch (player->profile.uri_type) {
3687 case MM_PLAYER_URI_TYPE_FILE:
3688 element = __mmplayer_gst_make_file_src(player);
3690 case MM_PLAYER_URI_TYPE_URL_HTTP:
3691 element = __mmplayer_gst_make_http_src(player);
3694 LOGE("not support uri type %d", player->profile.uri_type);
3699 LOGE("failed to create source element");
3708 __mmplayer_gst_build_es_pipeline(mm_player_t *player)
3710 MMHandleType attrs = 0;
3713 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3714 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3716 /* get profile attribute */
3717 attrs = MMPLAYER_GET_ATTRS(player);
3719 LOGE("failed to get content attribute");
3720 return MM_ERROR_PLAYER_INTERNAL;
3723 SECURE_LOGD("uri : %s", player->profile.uri);
3725 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3726 if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3727 LOGE("failed to commit");
3729 if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3730 return MM_ERROR_PLAYER_INTERNAL;
3732 if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3733 return MM_ERROR_PLAYER_INTERNAL;
3735 if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3736 return MM_ERROR_PLAYER_INTERNAL;
3739 return MM_ERROR_NONE;
3743 __mmplayer_gst_build_pipeline(mm_player_t *player)
3745 MMPlayerGstElement *mainbin = NULL;
3746 GstElement *src_elem = NULL;
3747 GstElement *autoplug_elem = NULL;
3748 GList *element_bucket = NULL;
3749 MMHandleType attrs = 0;
3750 enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3753 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3754 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3756 /* get profile attribute */
3757 attrs = MMPLAYER_GET_ATTRS(player);
3759 LOGE("failed to get content attribute");
3760 return MM_ERROR_PLAYER_INTERNAL;
3763 LOGD("uri type %d", player->profile.uri_type);
3765 /* create source element */
3766 switch (player->profile.uri_type) {
3767 case MM_PLAYER_URI_TYPE_URL_RTSP:
3768 src_elem = __mmplayer_gst_make_rtsp_src(player);
3770 case MM_PLAYER_URI_TYPE_URL_HTTP:
3771 src_elem = __mmplayer_gst_make_http_src(player);
3773 case MM_PLAYER_URI_TYPE_FILE:
3774 src_elem = __mmplayer_gst_make_file_src(player);
3776 case MM_PLAYER_URI_TYPE_SS:
3778 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3779 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3781 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3785 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3786 LOGD("get timeout from ini");
3787 http_timeout = player->ini.http_timeout;
3790 /* setting property to streaming source */
3791 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3794 case MM_PLAYER_URI_TYPE_MEM:
3796 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3798 src_elem = gst_element_factory_make("appsrc", "mem-source");
3800 LOGE("failed to create appsrc element");
3804 g_object_set(src_elem, "stream-type", stream_type,
3805 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3807 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3808 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3809 __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3810 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3814 LOGE("not support uri type");
3819 LOGE("failed to create source element");
3820 return MM_ERROR_PLAYER_INTERNAL;
3823 mainbin = player->pipeline->mainbin;
3825 /* take source element */
3826 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3828 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3829 mainbin[MMPLAYER_M_SRC].gst = src_elem;
3830 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3832 /* create next element for auto-plugging */
3833 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3834 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3835 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3836 if (!autoplug_elem) {
3837 LOGE("failed to create typefind element");
3841 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3842 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3843 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3844 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3845 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3846 if (!autoplug_elem) {
3847 LOGE("failed to create decodebin");
3851 /* default size of mq in decodebin is 2M
3852 * but it can cause blocking issue during seeking depends on content. */
3853 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3856 if (autoplug_elem) {
3857 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3858 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3859 mainbin[autoplug_elem_id].gst = autoplug_elem;
3861 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3864 /* add elements to pipeline */
3865 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3866 LOGE("failed to add elements to pipeline");
3870 /* linking elements in the bucket by added order. */
3871 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3872 LOGE("failed to link some elements");
3876 /* FIXME: need to check whether this is required or not. */
3877 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3878 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3879 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3880 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3882 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3883 LOGE("failed to create fakesink");
3886 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3888 /* take ownership of fakesink. we are reusing it */
3889 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3891 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3892 LOGE("failed to add fakesink to bin");
3893 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3898 g_list_free(element_bucket);
3901 return MM_ERROR_NONE;
3904 g_list_free(element_bucket);
3906 if (mainbin[MMPLAYER_M_SRC].gst)
3907 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3909 if (mainbin[autoplug_elem_id].gst)
3910 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3912 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3913 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3915 mainbin[MMPLAYER_M_SRC].gst = NULL;
3916 mainbin[autoplug_elem_id].gst = NULL;
3917 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3919 return MM_ERROR_PLAYER_INTERNAL;
3923 __mmplayer_gst_add_bus_watch(mm_player_t *player)
3926 MMPlayerGstElement *mainbin = NULL;
3929 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3930 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3932 mainbin = player->pipeline->mainbin;
3934 /* connect bus callback */
3935 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3937 LOGE("cannot get bus from pipeline");
3938 return MM_ERROR_PLAYER_INTERNAL;
3941 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3942 player->context.thread_default = g_main_context_get_thread_default();
3943 if (player->context.thread_default == NULL) {
3944 player->context.thread_default = g_main_context_default();
3945 LOGD("thread-default context is the global default context");
3947 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3949 /* set sync handler to get tag synchronously */
3950 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3951 gst_object_unref(GST_OBJECT(bus));
3953 /* create gst bus_msb_cb thread */
3954 g_mutex_init(&player->bus_msg_thread_mutex);
3955 g_cond_init(&player->bus_msg_thread_cond);
3956 player->bus_msg_thread_exit = FALSE;
3957 player->bus_msg_thread =
3958 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3959 if (!player->bus_msg_thread) {
3960 LOGE("failed to create gst BUS msg thread");
3961 g_mutex_clear(&player->bus_msg_thread_mutex);
3962 g_cond_clear(&player->bus_msg_thread_cond);
3963 return MM_ERROR_PLAYER_INTERNAL;
3967 return MM_ERROR_NONE;