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 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
60 count = gst_tag_list_get_tag_size(list, tag);
62 LOGD("count = %d", count);
64 for (i = 0; i < count; i++) {
67 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
68 if (!gst_tag_list_get_string_index(list, tag, i, &str))
69 g_assert_not_reached();
71 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
75 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
77 g_print(" : %s", str);
85 __mmplayer_is_hls_type(gchar *type) {
86 if (g_strrstr(type, "application/x-hls"))
92 __mmplayer_is_mpegts_type(gchar *type) {
93 if (g_strrstr(type, "video/mpegts"))
99 __mmplayer_is_mp3_type(gchar *type) {
100 if (g_strrstr(type, "application/x-id3") ||
101 (g_strrstr(type, "audio/mpeg") && g_strrstr(type, "mpegversion=(int)1")))
107 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
109 /* check whether the error is posted from not-activated track or not */
111 gint active_index = 0;
113 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
115 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
116 LOGD("current active pad index -%d", active_index);
118 if (src_element_name) {
121 if (player->audio_decoders) {
122 GList *adec = player->audio_decoders;
123 for (; adec ; adec = g_list_next(adec)) {
124 gchar *name = adec->data;
126 LOGD("found audio decoder name = %s", name);
127 if (g_strrstr(name, src_element_name)) {
134 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
137 if (active_index != msg_src_pos) {
138 LOGD("skip error because error is posted from no activated track");
146 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
148 /* Demuxer can't parse one track because it's corrupted.
149 * So, the decoder for it is not linked.
150 * But, it has one playable track.
152 if (g_strrstr(klass, "Demux")) {
153 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
154 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
155 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
156 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
158 if (player->pipeline->audiobin) { // PCM
159 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
161 LOGD("not found any available codec. Player should be destroyed.");
162 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
167 return MM_ERROR_PLAYER_INVALID_STREAM;
171 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
173 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
174 LOGE("Not supported subtitle.");
175 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
177 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
181 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
183 /* Decoder Custom Message */
184 if (!strstr(error->message, "ongoing"))
185 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
187 if (strncasecmp(klass, "audio", 5)) {
188 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
189 LOGD("Video can keep playing.");
190 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
192 } else if (strncasecmp(klass, "video", 5)) {
193 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
194 LOGD("Audio can keep playing.");
195 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
199 LOGD("not found any available codec. Player should be destroyed.");
200 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
204 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
206 if (strstr(error->message, "rights expired"))
207 return MM_ERROR_PLAYER_DRM_EXPIRED;
208 else if (strstr(error->message, "no rights"))
209 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
210 else if (strstr(error->message, "has future rights"))
211 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
212 else if (strstr(error->message, "opl violation"))
213 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
215 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
218 /* NOTE : decide gstreamer state whether there is some playable track or not. */
220 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
222 gchar *src_element_name = NULL;
223 GstElement *src_element = NULL;
224 GstElementFactory *factory = NULL;
225 const gchar *klass = NULL;
229 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
230 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
231 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
232 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
234 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
236 src_element = GST_ELEMENT_CAST(message->src);
237 src_element_name = GST_ELEMENT_NAME(src_element);
238 if (!src_element_name)
239 return MM_ERROR_PLAYER_INTERNAL;
241 factory = gst_element_get_factory(src_element);
243 return MM_ERROR_PLAYER_INTERNAL;
245 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
247 return MM_ERROR_PLAYER_INTERNAL;
249 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
250 error->code, error->message, src_element_name, klass);
252 if (MMPLAYER_USE_DECODEBIN(player) &&
253 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
254 return MM_ERROR_NONE;
256 switch (error->code) {
257 case GST_STREAM_ERROR_DECODE:
258 return __mmplayer_gst_transform_error_decode(player, klass);
259 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
260 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
261 case GST_STREAM_ERROR_WRONG_TYPE:
262 return __mmplayer_gst_transform_error_type(player, src_element);
263 case GST_STREAM_ERROR_FAILED:
264 return __mmplayer_gst_transform_error_failed(player, klass, error);
265 case GST_STREAM_ERROR_DECRYPT:
266 case GST_STREAM_ERROR_DECRYPT_NOKEY:
267 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
268 return __mmplayer_gst_transform_error_decrypt(player, error);
275 return MM_ERROR_PLAYER_INVALID_STREAM;
279 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
281 gint trans_err = MM_ERROR_NONE;
285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
288 case GST_CORE_ERROR_MISSING_PLUGIN:
289 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
290 case GST_CORE_ERROR_STATE_CHANGE:
291 case GST_CORE_ERROR_SEEK:
292 case GST_CORE_ERROR_NOT_IMPLEMENTED:
293 case GST_CORE_ERROR_FAILED:
294 case GST_CORE_ERROR_TOO_LAZY:
295 case GST_CORE_ERROR_PAD:
296 case GST_CORE_ERROR_THREAD:
297 case GST_CORE_ERROR_NEGOTIATION:
298 case GST_CORE_ERROR_EVENT:
299 case GST_CORE_ERROR_CAPS:
300 case GST_CORE_ERROR_TAG:
301 case GST_CORE_ERROR_CLOCK:
302 case GST_CORE_ERROR_DISABLED:
304 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
314 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
316 gint trans_err = MM_ERROR_NONE;
320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
323 case GST_LIBRARY_ERROR_FAILED:
324 case GST_LIBRARY_ERROR_TOO_LAZY:
325 case GST_LIBRARY_ERROR_INIT:
326 case GST_LIBRARY_ERROR_SHUTDOWN:
327 case GST_LIBRARY_ERROR_SETTINGS:
328 case GST_LIBRARY_ERROR_ENCODE:
330 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
340 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
342 gint trans_err = MM_ERROR_NONE;
346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
349 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
350 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
352 case GST_RESOURCE_ERROR_NOT_FOUND:
353 case GST_RESOURCE_ERROR_OPEN_READ:
354 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
355 || MMPLAYER_IS_RTSP_STREAMING(player)) {
356 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
359 case GST_RESOURCE_ERROR_READ:
360 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
361 || MMPLAYER_IS_RTSP_STREAMING(player)) {
362 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
364 } else if (message != NULL && message->src != NULL) {
365 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
366 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
368 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
369 path_type = MMPLAYER_PATH_VOD;
370 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
371 path_type = MMPLAYER_PATH_TEXT;
373 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
374 /* check storage state */
375 storage_get_state(player->storage_info[path_type].id, &storage_state);
376 player->storage_info[path_type].state = storage_state;
377 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
380 case GST_RESOURCE_ERROR_WRITE:
381 case GST_RESOURCE_ERROR_FAILED:
382 case GST_RESOURCE_ERROR_SEEK:
383 case GST_RESOURCE_ERROR_TOO_LAZY:
384 case GST_RESOURCE_ERROR_BUSY:
385 case GST_RESOURCE_ERROR_OPEN_WRITE:
386 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
387 case GST_RESOURCE_ERROR_CLOSE:
388 case GST_RESOURCE_ERROR_SYNC:
389 case GST_RESOURCE_ERROR_SETTINGS:
391 trans_err = MM_ERROR_PLAYER_INTERNAL;
401 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
403 gint trans_err = MM_ERROR_NONE;
407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
408 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
409 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
411 switch (error->code) {
412 case GST_STREAM_ERROR_FAILED:
413 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
414 case GST_STREAM_ERROR_DECODE:
415 case GST_STREAM_ERROR_WRONG_TYPE:
416 case GST_STREAM_ERROR_DECRYPT:
417 case GST_STREAM_ERROR_DECRYPT_NOKEY:
418 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
419 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
422 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
423 case GST_STREAM_ERROR_TOO_LAZY:
424 case GST_STREAM_ERROR_ENCODE:
425 case GST_STREAM_ERROR_DEMUX:
426 case GST_STREAM_ERROR_MUX:
427 case GST_STREAM_ERROR_FORMAT:
429 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
439 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
441 MMMessageParamType msg_param;
442 gchar *msg_src_element;
446 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
447 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
449 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
451 memset(&msg_param, 0, sizeof(MMMessageParamType));
453 if (error->domain == GST_CORE_ERROR) {
454 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
455 } else if (error->domain == GST_LIBRARY_ERROR) {
456 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
457 } else if (error->domain == GST_RESOURCE_ERROR) {
458 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
459 } else if (error->domain == GST_STREAM_ERROR) {
460 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
462 LOGW("This error domain is not defined.");
464 /* we treat system error as an internal error */
465 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
469 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
471 msg_param.data = (void *)error->message;
473 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
474 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
478 if (msg_param.code == MM_ERROR_NONE)
481 /* skip error to avoid duplicated posting */
482 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
483 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
484 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
485 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
487 /* The error will be handled by mused.
488 * @ref _mmplayer_manage_external_storage_state() */
490 LOGW("storage is removed, skip error post");
494 /* post error to application */
495 if (!player->msg_posted) {
496 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
497 /* don't post more if one was sent already */
498 player->msg_posted = TRUE;
500 LOGD("skip error post because it's sent already.");
509 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
512 MMMessageParamType msg_param;
513 gchar *msg_src_element = NULL;
514 GstStructure *s = NULL;
516 gchar *error_string = NULL;
520 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
521 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
523 s = gst_structure_copy(gst_message_get_structure(message));
526 if (!gst_structure_get_uint(s, "error_id", &error_id))
527 error_id = MMPLAYER_STREAMING_ERROR_NONE;
530 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
533 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
536 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
539 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
542 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
545 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
548 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
551 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
554 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
557 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
560 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
563 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
566 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
569 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
572 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
575 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
578 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
581 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
584 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
587 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
590 case MMPLAYER_STREAMING_ERROR_GONE:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
593 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
596 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
599 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
602 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
605 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
608 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
611 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
614 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
617 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
620 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
623 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
626 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
629 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
632 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
635 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
636 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
638 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
639 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
641 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
642 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
644 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
645 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
647 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
648 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
650 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
651 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
653 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
654 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
656 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
657 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
659 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
660 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
662 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
663 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
667 gst_structure_free(s);
668 return MM_ERROR_PLAYER_STREAMING_FAIL;
672 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
674 msg_param.data = (void *)error_string;
677 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
679 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
680 msg_src_element, msg_param.code, (char *)msg_param.data);
683 /* post error to application */
684 if (!player->msg_posted) {
685 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
687 /* don't post more if one was sent already */
688 player->msg_posted = TRUE;
690 LOGD("skip error post because it's sent already.");
693 gst_structure_free(s);
694 MMPLAYER_FREEIF(error_string);
702 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
704 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
705 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
706 gst_tag_list_get_string(tags, "stitching_software",
707 &metadata->stitching_software);
708 gst_tag_list_get_string(tags, "projection_type",
709 &metadata->projection_type_string);
710 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
711 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
712 gst_tag_list_get_int(tags, "init_view_heading",
713 &metadata->init_view_heading);
714 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
715 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
716 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
717 gst_tag_list_get_int(tags, "full_pano_width_pixels",
718 &metadata->full_pano_width_pixels);
719 gst_tag_list_get_int(tags, "full_pano_height_pixels",
720 &metadata->full_pano_height_pixels);
721 gst_tag_list_get_int(tags, "cropped_area_image_width",
722 &metadata->cropped_area_image_width);
723 gst_tag_list_get_int(tags, "cropped_area_image_height",
724 &metadata->cropped_area_image_height);
725 gst_tag_list_get_int(tags, "cropped_area_left",
726 &metadata->cropped_area_left);
727 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
728 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
729 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
730 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
734 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
737 /* macro for better code readability */
738 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
740 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
741 if (string != NULL) { \
742 SECURE_LOGD("update tag string : %s", string); \
743 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
744 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
745 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
746 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
747 mm_player_set_attribute((MMHandleType)player, NULL,\
748 playertag, new_string, strlen(new_string), NULL); \
749 MMPLAYER_FREEIF(new_string); \
751 mm_player_set_attribute((MMHandleType)player, NULL,\
752 playertag, string, strlen(string), NULL); \
754 MMPLAYER_FREEIF(string); \
759 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
761 GstSample *sample = NULL;\
762 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
763 GstMapInfo info = GST_MAP_INFO_INIT;\
764 buffer = gst_sample_get_buffer(sample);\
765 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
766 LOGD("failed to get image data from tag");\
767 gst_sample_unref(sample);\
770 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
771 MMPLAYER_FREEIF(player->album_art);\
772 player->album_art = (gchar *)g_malloc(info.size);\
773 if (player->album_art) {\
774 memcpy(player->album_art, info.data, info.size);\
775 mm_player_set_attribute((MMHandleType)player, NULL,\
776 playertag, (void *)player->album_art, info.size, NULL); \
777 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
778 msg_param.data = (void *)player->album_art;\
779 msg_param.size = info.size;\
780 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
781 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
784 gst_buffer_unmap(buffer, &info);\
785 gst_sample_unref(sample);\
789 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
791 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
794 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
795 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
796 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
797 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
798 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
800 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
801 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
802 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
803 mm_player_set_attribute((MMHandleType)player, NULL,\
804 "content_audio_bitrate", v_uint, NULL); \
805 player->bitrate[track_type] = v_uint; \
806 player->total_bitrate = 0; \
807 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
808 player->total_bitrate += player->bitrate[i]; \
809 mm_player_set_attribute((MMHandleType)player, NULL,\
810 playertag, player->total_bitrate, NULL); \
811 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
812 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
813 player->maximum_bitrate[track_type] = v_uint; \
814 player->total_maximum_bitrate = 0; \
815 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
816 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
817 mm_player_set_attribute((MMHandleType)player, NULL,\
818 playertag, player->total_maximum_bitrate, NULL); \
819 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
821 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
828 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
830 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
832 string = g_strdup_printf("%d", g_date_get_year(date));\
833 mm_player_set_attribute((MMHandleType)player, NULL,\
834 playertag, string, strlen(string), NULL); \
835 SECURE_LOGD("metainfo year : %s", string);\
836 MMPLAYER_FREEIF(string);\
842 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
844 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
845 if (datetime != NULL) {\
846 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
847 mm_player_set_attribute((MMHandleType)player, NULL,\
848 playertag, string, strlen(string), NULL); \
849 SECURE_LOGD("metainfo year : %s", string);\
850 MMPLAYER_FREEIF(string);\
851 gst_date_time_unref(datetime);\
857 GstTagList *tag_list = NULL;
862 GstDateTime *datetime = NULL;
864 GstBuffer *buffer = NULL;
866 MMMessageParamType msg_param = {0, };
868 /* currently not used. but those are needed for above macro */
869 //guint64 v_uint64 = 0;
870 //gdouble v_double = 0;
872 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
874 /* get tag list from gst message */
875 gst_message_parse_tag(msg, &tag_list);
877 /* store tags to player attributes */
878 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
879 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
880 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
881 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
882 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
883 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
884 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
885 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
886 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
887 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
888 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
889 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
890 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
891 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
892 MMPLAYER_UPDATE_TAG_LOCK(player);
893 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
894 MMPLAYER_UPDATE_TAG_UNLOCK(player);
895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
897 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
898 if (player->video360_metadata.is_spherical == -1) {
899 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
900 mm_player_set_attribute((MMHandleType)player, NULL,
901 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
902 if (player->video360_metadata.is_spherical == 1) {
903 LOGD("This is spherical content for 360 playback.");
904 player->is_content_spherical = TRUE;
906 LOGD("This is not spherical content");
907 player->is_content_spherical = FALSE;
910 if (player->video360_metadata.projection_type_string) {
911 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
912 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
914 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
915 player->is_content_spherical = player->is_video360_enabled = FALSE;
919 if (player->video360_metadata.stereo_mode_string) {
920 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
921 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
922 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
923 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
924 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
925 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
927 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
928 player->is_content_spherical = player->is_video360_enabled = FALSE;
934 gst_tag_list_unref(tag_list);
939 /* if retval is FALSE, it will be dropped for performance. */
941 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
943 gboolean retval = FALSE;
945 if (!(player->pipeline && player->pipeline->mainbin)) {
946 LOGE("player pipeline handle is null");
950 switch (GST_MESSAGE_TYPE(message)) {
951 case GST_MESSAGE_TAG:
952 case GST_MESSAGE_EOS:
953 case GST_MESSAGE_ERROR:
954 case GST_MESSAGE_WARNING:
955 case GST_MESSAGE_CLOCK_LOST:
956 case GST_MESSAGE_NEW_CLOCK:
957 case GST_MESSAGE_ELEMENT:
958 case GST_MESSAGE_DURATION_CHANGED:
959 case GST_MESSAGE_ASYNC_START:
960 case GST_MESSAGE_STREAM_COLLECTION:
963 case GST_MESSAGE_ASYNC_DONE:
964 case GST_MESSAGE_STATE_CHANGED:
965 /* we only handle messages from pipeline */
966 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
971 case GST_MESSAGE_BUFFERING:
973 gint buffer_percent = 0;
976 gst_message_parse_buffering(message, &buffer_percent);
977 if (buffer_percent != MAX_BUFFER_PERCENT) {
978 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
982 if (!MMPLAYER_CMD_TRYLOCK(player)) {
983 LOGW("can't get cmd lock, send msg to bus");
987 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
988 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
989 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
992 MMPLAYER_CMD_UNLOCK(player);
996 case GST_MESSAGE_STREAMS_SELECTED:
998 if (MMPLAYER_USE_DECODEBIN(player))
999 break; /* drop msg */
1001 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1002 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1003 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1005 gint64 dur_bytes = 0L;
1007 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1008 LOGE("fail to get duration.");
1010 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1011 * use file information was already set on Q2 when it was created. */
1012 _mm_player_streaming_set_queue2(player->streamer,
1013 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1014 TRUE, /* use_buffering */
1015 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1016 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1019 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1020 player->no_more_pad = TRUE;
1021 _mmplayer_set_reconfigure_state(player, FALSE);
1022 _mmplayer_pipeline_complete(NULL, player);
1035 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1037 guint64 data_size = 0;
1038 gint64 pos_nsec = 0;
1040 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1042 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1044 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1045 data_size = player->http_content_size;
1048 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1049 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1055 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1057 int ret = MM_ERROR_NONE;
1058 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1059 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1060 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1061 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1063 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1064 LOGW("do nothing for buffering msg");
1065 ret = MM_ERROR_PLAYER_INVALID_STATE;
1069 prev_state = MMPLAYER_PREV_STATE(player);
1070 current_state = MMPLAYER_CURRENT_STATE(player);
1071 target_state = MMPLAYER_TARGET_STATE(player);
1072 pending_state = MMPLAYER_PENDING_STATE(player);
1074 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1075 MMPLAYER_STATE_GET_NAME(prev_state),
1076 MMPLAYER_STATE_GET_NAME(current_state),
1077 MMPLAYER_STATE_GET_NAME(pending_state),
1078 MMPLAYER_STATE_GET_NAME(target_state),
1079 player->streamer->buffering_state);
1081 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1082 /* NOTE : if buffering has done, player has to go to target state. */
1083 switch (target_state) {
1084 case MM_PLAYER_STATE_PAUSED:
1086 switch (pending_state) {
1087 case MM_PLAYER_STATE_PLAYING:
1088 _mmplayer_gst_pause(player, TRUE);
1091 case MM_PLAYER_STATE_PAUSED:
1092 LOGD("player is already going to paused state, there is nothing to do.");
1095 case MM_PLAYER_STATE_NONE:
1096 case MM_PLAYER_STATE_NULL:
1097 case MM_PLAYER_STATE_READY:
1099 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1105 case MM_PLAYER_STATE_PLAYING:
1107 switch (pending_state) {
1108 case MM_PLAYER_STATE_NONE:
1110 if (current_state != MM_PLAYER_STATE_PLAYING)
1111 _mmplayer_gst_resume(player, TRUE);
1115 case MM_PLAYER_STATE_PAUSED:
1116 /* NOTE: It should be worked as asynchronously.
1117 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1119 if (current_state == MM_PLAYER_STATE_PLAYING) {
1120 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1121 * The current state should be changed to paused purposely to prevent state conflict.
1123 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1125 _mmplayer_gst_resume(player, TRUE);
1128 case MM_PLAYER_STATE_PLAYING:
1129 LOGD("player is already going to playing state, there is nothing to do.");
1132 case MM_PLAYER_STATE_NULL:
1133 case MM_PLAYER_STATE_READY:
1135 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1141 case MM_PLAYER_STATE_NULL:
1142 case MM_PLAYER_STATE_READY:
1143 case MM_PLAYER_STATE_NONE:
1145 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1149 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1150 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1152 switch (pending_state) {
1153 case MM_PLAYER_STATE_NONE:
1155 if (current_state != MM_PLAYER_STATE_PAUSED) {
1156 /* rtsp streaming pause makes rtsp server stop sending data. */
1157 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1158 LOGD("set pause state during buffering");
1159 _mmplayer_gst_pause(player, TRUE);
1165 case MM_PLAYER_STATE_PLAYING:
1166 /* rtsp streaming pause makes rtsp server stop sending data. */
1167 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1168 _mmplayer_gst_pause(player, TRUE);
1171 case MM_PLAYER_STATE_PAUSED:
1174 case MM_PLAYER_STATE_NULL:
1175 case MM_PLAYER_STATE_READY:
1177 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1186 static stream_variant_t *
1187 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1189 stream_variant_t *var_info = NULL;
1190 g_return_val_if_fail(self != NULL, NULL);
1192 var_info = g_new0(stream_variant_t, 1);
1193 if (!var_info) return NULL;
1194 var_info->bandwidth = self->bandwidth;
1195 var_info->width = self->width;
1196 var_info->height = self->height;
1201 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1207 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1208 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1210 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1211 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1212 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1214 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1215 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1216 player->http_content_size = (bytes > 0) ? bytes : 0;
1219 /* handling audio clip which has vbr. means duration is keep changing */
1220 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1229 __mmplayer_eos_timer_cb(gpointer u_data)
1231 mmplayer_t *player = NULL;
1232 MMHandleType attrs = 0;
1235 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1237 player = (mmplayer_t *)u_data;
1238 attrs = MMPLAYER_GET_ATTRS(player);
1240 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1244 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1245 if (ret_value != MM_ERROR_NONE)
1246 LOGE("seeking to 0 failed in repeat play");
1249 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1252 /* we are returning FALSE as we need only one posting */
1257 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1259 MMPLAYER_RETURN_IF_FAIL(player);
1261 /* post now if delay is zero */
1262 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1263 LOGD("eos delay is zero. posting EOS now");
1264 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1266 if (player->audio_decoded_cb)
1267 _mmplayer_cancel_eos_timer(player);
1272 /* cancel if existing */
1273 _mmplayer_cancel_eos_timer(player);
1275 /* init new timeout */
1276 /* NOTE : consider give high priority to this timer */
1277 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1279 player->eos_timer = g_timeout_add(delay_in_ms,
1280 __mmplayer_eos_timer_cb, player);
1282 player->context.global_default = g_main_context_default();
1283 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1285 /* check timer is valid. if not, send EOS now */
1286 if (player->eos_timer == 0) {
1287 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1288 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1293 __mmplayer_gst_pending_seek(mmplayer_t *player)
1295 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1296 int ret = MM_ERROR_NONE;
1300 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1302 if (!player->pending_seek.is_pending) {
1303 LOGD("pending seek is not reserved. nothing to do.");
1307 /* check player state if player could pending seek or not. */
1308 current_state = MMPLAYER_CURRENT_STATE(player);
1310 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1311 LOGW("try to pending seek in %s state, try next time. ",
1312 MMPLAYER_STATE_GET_NAME(current_state));
1316 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1318 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1319 if (ret != MM_ERROR_NONE)
1320 LOGE("failed to seek pending position. just keep staying current position.");
1322 player->pending_seek.is_pending = false;
1330 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1332 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1334 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1336 audiobin = player->pipeline->audiobin; /* can be null */
1337 videobin = player->pipeline->videobin; /* can be null */
1338 textbin = player->pipeline->textbin; /* can be null */
1340 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1342 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1343 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1345 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1346 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1348 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1349 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1355 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1357 mmplayer_gst_element_t *textbin;
1360 MMPLAYER_RETURN_IF_FAIL(player &&
1362 player->pipeline->textbin);
1364 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1366 textbin = player->pipeline->textbin;
1369 LOGD("Drop subtitle text after getting EOS");
1371 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1372 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1374 player->is_subtitle_force_drop = TRUE;
1376 if (player->is_subtitle_force_drop == TRUE) {
1377 LOGD("Enable subtitle data path without drop");
1379 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1380 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1382 LOGD("non-connected with external display");
1384 player->is_subtitle_force_drop = FALSE;
1390 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1392 MMHandleType attrs = 0;
1397 /* NOTE : EOS event is coming multiple time. watch out it */
1398 /* check state. we only process EOS when pipeline state goes to PLAYING */
1399 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1400 LOGD("EOS received on non-playing state. ignoring it");
1404 if (player->pipeline && player->pipeline->textbin)
1405 __mmplayer_drop_subtitle(player, TRUE);
1407 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1408 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1410 /* rewind if repeat count is greater then zero */
1411 /* get play count */
1412 attrs = MMPLAYER_GET_ATTRS(player);
1414 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1416 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1418 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1419 if (player->playback_rate < 0.0) {
1420 player->resumed_by_rewind = TRUE;
1421 _mmplayer_set_mute((MMHandleType)player, false);
1422 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1425 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1428 player->sent_bos = FALSE;
1430 LOGD("do not post eos msg for repeating");
1435 if (player->pipeline)
1436 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1438 /* post eos message to application */
1439 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1441 /* reset last position */
1442 player->last_position = 0;
1449 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1451 GError *error = NULL;
1452 gchar *debug = NULL;
1456 /* generating debug info before returning error */
1457 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1459 /* get error code */
1460 gst_message_parse_error(msg, &error, &debug);
1462 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1463 /* Note : the streaming error from the streaming source is handled
1464 * using __mmplayer_handle_streaming_error.
1466 __mmplayer_handle_streaming_error(player, msg);
1468 /* dump state of all element */
1469 _mmplayer_dump_pipeline_state(player);
1471 /* translate gst error code to msl error code. then post it
1472 * to application if needed
1474 __mmplayer_handle_gst_error(player, msg, error);
1477 LOGE("error debug : %s", debug);
1480 MMPLAYER_FREEIF(debug);
1481 g_error_free(error);
1488 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1490 MMMessageParamType msg_param = {0, };
1491 int bRet = MM_ERROR_NONE;
1494 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1496 if (!MMPLAYER_IS_STREAMING(player)) {
1497 LOGW("this is not streaming playback.");
1501 MMPLAYER_CMD_LOCK(player);
1503 if (!player->streamer) {
1504 LOGW("Pipeline is shutting down");
1505 MMPLAYER_CMD_UNLOCK(player);
1509 /* ignore the remained buffering message till getting 100% msg */
1510 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1511 gint buffer_percent = 0;
1513 gst_message_parse_buffering(msg, &buffer_percent);
1515 if (buffer_percent == MAX_BUFFER_PERCENT) {
1516 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1517 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1518 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1520 MMPLAYER_CMD_UNLOCK(player);
1524 /* ignore the remained buffering message */
1525 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1526 gint buffer_percent = 0;
1528 gst_message_parse_buffering(msg, &buffer_percent);
1530 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1531 player->streamer->buffering_percent, buffer_percent);
1533 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1534 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1535 player->streamer->buffering_req.is_pre_buffering = FALSE;
1537 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1539 LOGD("interrupted buffering - ignored the remained buffering msg!");
1540 MMPLAYER_CMD_UNLOCK(player);
1545 __mmplayer_update_buffer_setting(player, msg);
1547 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1549 if (bRet == MM_ERROR_NONE) {
1550 msg_param.connection.buffering = player->streamer->buffering_percent;
1551 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1553 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1554 player->pending_resume &&
1555 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1557 player->is_external_subtitle_added_now = FALSE;
1558 player->pending_resume = FALSE;
1559 _mmplayer_resume((MMHandleType)player);
1562 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1563 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1565 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1566 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1567 player->seek_state = MMPLAYER_SEEK_NONE;
1568 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1569 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1570 /* Considering the async state transition in case of RTSP.
1571 After getting state change gst msg, seek completed msg will be posted. */
1572 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1576 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1577 if (!player->streamer) {
1578 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1579 MMPLAYER_CMD_UNLOCK(player);
1583 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1585 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1586 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1588 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1589 msg_param.connection.buffering = player->streamer->buffering_percent;
1590 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1592 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1595 msg_param.connection.buffering = player->streamer->buffering_percent;
1596 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1599 MMPLAYER_CMD_UNLOCK(player);
1607 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1609 mmplayer_gst_element_t *mainbin;
1610 const GValue *voldstate, *vnewstate, *vpending;
1611 GstState oldstate = GST_STATE_NULL;
1612 GstState newstate = GST_STATE_NULL;
1613 GstState pending = GST_STATE_NULL;
1616 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1618 mainbin = player->pipeline->mainbin;
1620 /* we only handle messages from pipeline */
1621 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1624 /* get state info from msg */
1625 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1626 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1627 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1629 if (!voldstate || !vnewstate) {
1630 LOGE("received msg has wrong format.");
1634 oldstate = (GstState)voldstate->data[0].v_int;
1635 newstate = (GstState)vnewstate->data[0].v_int;
1637 pending = (GstState)vpending->data[0].v_int;
1639 LOGD("state changed [%s] : %s ---> %s final : %s",
1640 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1641 gst_element_state_get_name((GstState)oldstate),
1642 gst_element_state_get_name((GstState)newstate),
1643 gst_element_state_get_name((GstState)pending));
1645 if (newstate == GST_STATE_PLAYING) {
1646 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1648 int retVal = MM_ERROR_NONE;
1649 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1651 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1653 if (MM_ERROR_NONE != retVal)
1654 LOGE("failed to seek pending position. just keep staying current position.");
1656 player->pending_seek.is_pending = false;
1660 if (oldstate == newstate) {
1661 LOGD("pipeline reports state transition to old state");
1666 case GST_STATE_PAUSED:
1668 gboolean prepare_async = FALSE;
1670 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1671 // managed prepare async case
1672 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1673 LOGD("checking prepare mode for async transition - %d", prepare_async);
1676 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1677 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1679 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1680 _mm_player_streaming_set_content_bitrate(player->streamer,
1681 player->total_maximum_bitrate, player->total_bitrate);
1683 if (player->pending_seek.is_pending) {
1684 LOGW("trying to do pending seek");
1685 MMPLAYER_CMD_LOCK(player);
1686 __mmplayer_gst_pending_seek(player);
1687 MMPLAYER_CMD_UNLOCK(player);
1693 case GST_STATE_PLAYING:
1695 if (MMPLAYER_IS_STREAMING(player)) {
1696 // managed prepare async case when buffering is completed
1697 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1698 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1699 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1700 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1702 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1704 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1705 if (player->streamer->buffering_percent < 100) {
1707 MMMessageParamType msg_param = {0, };
1708 LOGW("Posting Buffering Completed Message to Application !!!");
1710 msg_param.connection.buffering = 100;
1711 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1716 if (player->gapless.stream_changed) {
1717 _mmplayer_update_content_attrs(player, ATTR_ALL);
1718 player->gapless.stream_changed = FALSE;
1721 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1722 player->seek_state = MMPLAYER_SEEK_NONE;
1723 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1727 case GST_STATE_VOID_PENDING:
1728 case GST_STATE_NULL:
1729 case GST_STATE_READY:
1739 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1741 const gchar *structure_name;
1742 gint count = 0, idx = 0;
1745 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1747 if (gst_message_get_structure(msg) == NULL)
1750 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1751 if (!structure_name)
1754 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1756 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1757 const GValue *var_info = NULL;
1759 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1760 if (var_info != NULL) {
1761 if (player->adaptive_info.var_list)
1762 g_list_free_full(player->adaptive_info.var_list, g_free);
1764 /* share addr or copy the list */
1765 player->adaptive_info.var_list =
1766 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1768 count = g_list_length(player->adaptive_info.var_list);
1770 stream_variant_t *temp = NULL;
1772 /* print out for debug */
1773 LOGD("num of variant_info %d", count);
1774 for (idx = 0; idx < count; idx++) {
1775 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1777 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1783 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1784 gint num_buffers = 0;
1785 gint extra_num_buffers = 0;
1787 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1788 LOGD("video_num_buffers : %d", num_buffers);
1789 mm_player_set_attribute((MMHandleType)player, NULL,
1790 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1793 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1794 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1795 mm_player_set_attribute((MMHandleType)player, NULL,
1796 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1801 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1802 _mmplayer_track_update_text_attr_info(player, msg);
1804 /* custom message */
1805 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1806 MMMessageParamType msg_param = {0,};
1807 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1808 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1811 /* custom message for RTSP attribute :
1812 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1813 sdp which has contents info is received when rtsp connection is opened.
1814 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1815 if (!strcmp(structure_name, "rtspsrc_properties")) {
1816 gchar *audio_codec = NULL;
1817 gchar *video_codec = NULL;
1818 gchar *video_frame_size = NULL;
1820 gst_structure_get(gst_message_get_structure(msg),
1821 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1822 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1823 player->streaming_type = _mmplayer_get_stream_service_type(player);
1825 gst_structure_get(gst_message_get_structure(msg),
1826 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1827 LOGD("rtsp_audio_codec : %s", audio_codec);
1829 mm_player_set_attribute((MMHandleType)player, NULL,
1830 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1832 gst_structure_get(gst_message_get_structure(msg),
1833 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1834 LOGD("rtsp_video_codec : %s", video_codec);
1836 mm_player_set_attribute((MMHandleType)player, NULL,
1837 "content_video_codec", video_codec, strlen(video_codec), NULL);
1839 gst_structure_get(gst_message_get_structure(msg),
1840 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1841 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1842 if (video_frame_size) {
1843 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1844 mm_player_set_attribute((MMHandleType)player, NULL,
1845 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1846 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1848 g_strfreev(res_str);
1857 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1859 mmplayer_gst_element_t *mainbin;
1862 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1864 mainbin = player->pipeline->mainbin;
1866 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1868 /* we only handle messages from pipeline */
1869 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1872 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1873 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1874 player->seek_state = MMPLAYER_SEEK_NONE;
1875 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1876 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1877 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1878 LOGD("sync %s state(%s) with parent state(%s)",
1879 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1880 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1881 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1883 /* In case of streaming, pause is required before finishing seeking by buffering.
1884 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1885 Because the buffering state is controlled according to the state transition for force resume,
1886 the decodebin state should be paused as player state. */
1887 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1890 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1891 (player->streamer) &&
1892 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1893 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1894 GstQuery *query = NULL;
1895 gboolean busy = FALSE;
1898 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1899 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1900 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1901 gst_query_parse_buffering_percent(query, &busy, &percent);
1902 gst_query_unref(query);
1904 LOGD("buffered percent(%s): %d",
1905 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1909 __mmplayer_handle_buffering_playback(player);
1912 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1921 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1923 GValue val = { 0, };
1925 guint indent = GPOINTER_TO_UINT(user_data);
1927 if (!gst_tag_list_copy_value(&val, tags, tag))
1930 if (G_VALUE_HOLDS_STRING(&val))
1931 str = g_value_dup_string(&val);
1933 str = gst_value_serialize(&val);
1935 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1937 g_value_unset(&val);
1941 __mmplayer_dump_collection(GstStreamCollection * collection)
1944 GstTagList *tags = NULL;
1945 GstCaps *caps = NULL;
1947 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1948 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1949 LOGD ("collection: Stream %u type %s flags 0x%x\n", i,
1950 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1951 gst_stream_get_stream_flags(stream));
1952 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1954 caps = gst_stream_get_caps(stream);
1956 gchar *caps_str = gst_caps_to_string(caps);
1957 LOGD (" caps: %s\n", caps_str);
1959 gst_caps_unref(caps);
1962 tags = gst_stream_get_tags(stream);
1965 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1966 gst_tag_list_unref(tags);
1972 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1973 GstStream *stream, GParamSpec *pspec, gpointer data)
1975 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1976 gst_stream_get_stream_id(stream), pspec->name, collection);
1977 if (g_str_equal(pspec->name, "caps")) {
1978 GstCaps *caps = gst_stream_get_caps(stream);
1979 gchar *caps_str = gst_caps_to_string(caps);
1980 LOGD (" New caps: %s\n", caps_str);
1982 gst_caps_unref(caps);
1985 if (g_str_equal (pspec->name, "tags")) {
1986 GstTagList *tags = gst_stream_get_tags(stream);
1989 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1990 gst_tag_list_unref(tags);
1996 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1998 mmplayer_t *player = (mmplayer_t *)(data);
2000 MMPLAYER_RETURN_IF_FAIL(player);
2001 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2003 switch (GST_MESSAGE_TYPE(msg)) {
2004 case GST_MESSAGE_UNKNOWN:
2005 LOGD("unknown message received");
2008 case GST_MESSAGE_EOS:
2009 LOGD("GST_MESSAGE_EOS received");
2010 __mmplayer_gst_handle_eos_message(player, msg);
2013 case GST_MESSAGE_ERROR:
2014 _mmplayer_set_reconfigure_state(player, FALSE);
2015 __mmplayer_gst_handle_error_message(player, msg);
2018 case GST_MESSAGE_WARNING:
2021 GError *error = NULL;
2023 gst_message_parse_warning(msg, &error, &debug);
2025 LOGD("warning : %s", error->message);
2026 LOGD("debug : %s", debug);
2028 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2030 MMPLAYER_FREEIF(debug);
2031 g_error_free(error);
2035 case GST_MESSAGE_TAG:
2037 LOGD("GST_MESSAGE_TAG");
2038 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2039 LOGW("failed to extract tags from gstmessage");
2043 case GST_MESSAGE_BUFFERING:
2044 __mmplayer_gst_handle_buffering_message(player, msg);
2047 case GST_MESSAGE_STATE_CHANGED:
2048 __mmplayer_gst_handle_state_message(player, msg);
2051 case GST_MESSAGE_CLOCK_LOST:
2053 GstClock *clock = NULL;
2054 gboolean need_new_clock = FALSE;
2056 gst_message_parse_clock_lost(msg, &clock);
2057 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2059 if (!player->videodec_linked)
2060 need_new_clock = TRUE;
2061 else if (!player->ini.use_system_clock)
2062 need_new_clock = TRUE;
2064 if (need_new_clock) {
2065 LOGD("Provide clock is TRUE, do pause->resume");
2066 _mmplayer_gst_pause(player, FALSE);
2067 _mmplayer_gst_resume(player, FALSE);
2072 case GST_MESSAGE_NEW_CLOCK:
2074 GstClock *clock = NULL;
2075 gst_message_parse_new_clock(msg, &clock);
2076 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2080 case GST_MESSAGE_ELEMENT:
2081 __mmplayer_gst_handle_element_message(player, msg);
2084 case GST_MESSAGE_DURATION_CHANGED:
2086 LOGD("GST_MESSAGE_DURATION_CHANGED");
2087 if (!__mmplayer_gst_handle_duration(player, msg))
2088 LOGW("failed to update duration");
2092 case GST_MESSAGE_ASYNC_START:
2093 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2096 case GST_MESSAGE_ASYNC_DONE:
2097 __mmplayer_gst_handle_async_done_message(player, msg);
2099 case GST_MESSAGE_STREAM_COLLECTION:
2101 GstStreamCollection *collection = NULL;
2102 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2104 gst_message_parse_stream_collection(msg, &collection);
2106 __mmplayer_dump_collection(collection);
2107 if (player->collection && player->stream_notify_id) {
2108 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2109 player->stream_notify_id = 0;
2111 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2112 if (player->collection) {
2113 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2114 (GCallback)__mmplayer_stream_notify_cb, player);
2116 gst_object_unref(collection);
2119 case GST_MESSAGE_STREAMS_SELECTED:
2121 GstStreamCollection *collection = NULL;
2122 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2124 gst_message_parse_streams_selected(msg, &collection);
2126 guint i = 0, len = 0;
2127 len = gst_message_streams_selected_get_size(msg);
2128 for (i = 0; i < len; i++) {
2129 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2130 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2131 gst_object_unref(stream);
2133 gst_object_unref (collection);
2138 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2139 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2140 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2141 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2142 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2143 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2144 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2145 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2146 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2147 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2148 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2149 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2150 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2151 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2152 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2159 /* should not call 'gst_message_unref(msg)' */
2163 static GstBusSyncReply
2164 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2166 mmplayer_t *player = (mmplayer_t *)data;
2167 GstBusSyncReply reply = GST_BUS_DROP;
2169 if (!(player->pipeline && player->pipeline->mainbin)) {
2170 LOGE("player pipeline handle is null");
2171 return GST_BUS_PASS;
2174 if (!__mmplayer_gst_check_useful_message(player, message)) {
2175 gst_message_unref(message);
2176 return GST_BUS_DROP;
2179 switch (GST_MESSAGE_TYPE(message)) {
2180 case GST_MESSAGE_TAG:
2181 __mmplayer_gst_extract_tag_from_msg(player, message);
2185 GstTagList *tags = NULL;
2187 gst_message_parse_tag(message, &tags);
2189 LOGE("TAGS received from element \"%s\".",
2190 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2192 gst_tag_list_foreach(tags, print_tag, NULL);
2193 gst_tag_list_unref(tags);
2201 case GST_MESSAGE_DURATION_CHANGED:
2202 __mmplayer_gst_handle_duration(player, message);
2204 case GST_MESSAGE_ELEMENT:
2206 const gchar *klass = NULL;
2207 klass = gst_element_factory_get_metadata
2208 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2209 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2210 reply = GST_BUS_PASS;
2213 __mmplayer_gst_handle_element_message(player, message);
2216 case GST_MESSAGE_ASYNC_DONE:
2217 /* NOTE:Don't call gst_callback directly
2218 * because previous frame can be showed even though this message is received for seek.
2221 reply = GST_BUS_PASS;
2225 if (reply == GST_BUS_DROP)
2226 gst_message_unref(message);
2232 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2234 GstElement *appsrc = element;
2235 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2236 GstBuffer *buffer = NULL;
2237 GstFlowReturn ret = GST_FLOW_OK;
2240 MMPLAYER_RETURN_IF_FAIL(element);
2241 MMPLAYER_RETURN_IF_FAIL(buf);
2243 buffer = gst_buffer_new();
2245 if (buf->offset < 0 || buf->len < 0) {
2246 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2250 if (buf->offset >= buf->len) {
2251 LOGD("call eos appsrc");
2252 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2256 if (buf->len - buf->offset < size)
2257 len = buf->len - buf->offset;
2259 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2260 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2261 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2264 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2266 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2272 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2274 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2276 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2278 buf->offset = (int)size;
2284 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2286 mmplayer_t *player = (mmplayer_t *)user_data;
2287 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2288 MMMessageParamType msg_param = {0,};
2289 guint64 current_level_bytes = 0;
2291 MMPLAYER_RETURN_IF_FAIL(player);
2293 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2294 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2295 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2296 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2298 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2302 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2304 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2306 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2307 msg_param.buffer_status.stream_type = stream_type;
2308 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2309 msg_param.buffer_status.bytes = current_level_bytes;
2311 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2315 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2317 mmplayer_t *player = (mmplayer_t *)user_data;
2318 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2319 MMMessageParamType msg_param = {0,};
2320 guint64 current_level_bytes = 0;
2322 MMPLAYER_RETURN_IF_FAIL(player);
2324 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2325 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2326 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2327 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2329 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2333 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2335 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2337 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2338 msg_param.buffer_status.stream_type = stream_type;
2339 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2340 msg_param.buffer_status.bytes = current_level_bytes;
2342 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2346 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2348 mmplayer_t *player = (mmplayer_t *)user_data;
2349 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2350 MMMessageParamType msg_param = {0,};
2352 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2354 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2355 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2356 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2357 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2359 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2363 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2365 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2366 msg_param.seek_data.stream_type = stream_type;
2367 msg_param.seek_data.offset = position;
2369 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2375 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2377 #define MAX_LEN_NAME 20
2379 gboolean ret = FALSE;
2380 GstPad *sinkpad = NULL;
2381 gchar *prefix = NULL;
2382 gchar dec_name[MAX_LEN_NAME] = {0, };
2383 main_element_id_e elem_id = MMPLAYER_M_NUM;
2385 mmplayer_gst_element_t *mainbin = NULL;
2386 GstElement *decodebin = NULL;
2387 GstCaps *dec_caps = NULL;
2391 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2393 player->pipeline->mainbin, FALSE);
2394 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2396 mainbin = player->pipeline->mainbin;
2398 case MM_PLAYER_STREAM_TYPE_AUDIO:
2400 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2402 case MM_PLAYER_STREAM_TYPE_VIDEO:
2404 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2407 LOGE("invalid type %d", type);
2411 if (mainbin[elem_id].gst) {
2412 LOGE("elem(%d) is already created", elem_id);
2416 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2418 /* create decodebin */
2419 decodebin = gst_element_factory_make("decodebin", dec_name);
2421 LOGE("failed to create %s", dec_name);
2425 mainbin[elem_id].id = elem_id;
2426 mainbin[elem_id].gst = decodebin;
2428 /* raw pad handling signal */
2429 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2430 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2432 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2433 before looking for any elements that can handle that stream.*/
2434 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2435 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2437 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2438 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2439 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2441 /* This signal is emitted when a element is added to the bin.*/
2442 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2443 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2445 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2446 LOGE("failed to add new decodebin");
2450 dec_caps = gst_pad_query_caps(srcpad, NULL);
2453 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2455 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2456 gst_caps_unref(dec_caps);
2459 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2461 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2462 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2465 gst_object_unref(GST_OBJECT(sinkpad));
2467 gst_element_sync_state_with_parent(decodebin);
2473 gst_object_unref(GST_OBJECT(sinkpad));
2475 if (mainbin[elem_id].gst) {
2476 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2477 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2478 gst_object_unref(mainbin[elem_id].gst);
2479 mainbin[elem_id].gst = NULL;
2487 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2489 #define MAX_LEN_NAME 20
2490 mmplayer_gst_element_t *mainbin = NULL;
2491 gchar *prefix = NULL;
2492 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2494 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2495 GstElement *src = NULL, *queue = NULL;
2496 GstPad *srcpad = NULL;
2499 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2500 player->pipeline->mainbin, FALSE);
2502 mainbin = player->pipeline->mainbin;
2504 LOGD("type(%d) path is creating", type);
2506 case MM_PLAYER_STREAM_TYPE_AUDIO:
2508 if (mainbin[MMPLAYER_M_SRC].gst)
2509 src_id = MMPLAYER_M_2ND_SRC;
2511 src_id = MMPLAYER_M_SRC;
2512 queue_id = MMPLAYER_M_A_BUFFER;
2514 case MM_PLAYER_STREAM_TYPE_VIDEO:
2516 src_id = MMPLAYER_M_SRC;
2517 queue_id = MMPLAYER_M_V_BUFFER;
2519 case MM_PLAYER_STREAM_TYPE_TEXT:
2520 prefix = "subtitle";
2521 src_id = MMPLAYER_M_SUBSRC;
2522 queue_id = MMPLAYER_M_S_BUFFER;
2525 LOGE("invalid type %d", type);
2529 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2530 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2533 src = gst_element_factory_make("appsrc", src_name);
2535 LOGF("failed to create %s", src_name);
2539 mainbin[src_id].id = src_id;
2540 mainbin[src_id].gst = src;
2542 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2543 "caps", caps, NULL);
2545 /* size of many video frames are larger than default blocksize as 4096 */
2546 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2547 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2549 if (player->media_stream_buffer_max_size[type] > 0)
2550 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2552 if (player->media_stream_buffer_min_percent[type] > 0)
2553 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2555 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2556 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2558 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2559 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2560 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2561 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2562 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2563 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2566 queue = gst_element_factory_make("queue2", queue_name);
2568 LOGE("failed to create %s", queue_name);
2571 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2573 mainbin[queue_id].id = queue_id;
2574 mainbin[queue_id].gst = queue;
2576 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2577 LOGE("failed to add src");
2581 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2582 LOGE("failed to add queue");
2586 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2587 LOGE("failed to link src and queue");
2591 /* create decoder */
2592 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2594 LOGE("failed to get srcpad of queue");
2598 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2599 _mmplayer_gst_create_decoder(player, srcpad, caps);
2601 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2602 LOGE("failed to create decoder");
2603 gst_object_unref(GST_OBJECT(srcpad));
2607 gst_object_unref(GST_OBJECT(srcpad));
2611 if (mainbin[src_id].gst) {
2612 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2613 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2614 gst_object_unref(mainbin[src_id].gst);
2615 mainbin[src_id].gst = NULL;
2618 if (mainbin[queue_id].gst) {
2619 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2620 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2621 gst_object_unref(mainbin[queue_id].gst);
2622 mainbin[queue_id].gst = NULL;
2629 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2631 GstPad *sinkpad = NULL;
2632 GstCaps *caps = NULL;
2633 GstElement *new_element = NULL;
2634 GstStructure *str = NULL;
2635 const gchar *name = NULL;
2637 mmplayer_t *player = (mmplayer_t *)data;
2641 MMPLAYER_RETURN_IF_FAIL(element && pad);
2642 MMPLAYER_RETURN_IF_FAIL(player &&
2644 player->pipeline->mainbin);
2646 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2647 * num_dynamic_pad will decreased after creating a sinkbin.
2649 player->num_dynamic_pad++;
2650 LOGD("stream count inc : %d", player->num_dynamic_pad);
2652 caps = gst_pad_query_caps(pad, NULL);
2653 MMPLAYER_CHECK_NULL(caps);
2655 str = gst_caps_get_structure(caps, 0);
2656 name = gst_structure_get_string(str, "media");
2658 LOGE("cannot get mimetype from structure.");
2662 if (strstr(name, "video")) {
2664 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2666 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2667 if (player->v_stream_caps) {
2668 gst_caps_unref(player->v_stream_caps);
2669 player->v_stream_caps = NULL;
2672 new_element = gst_element_factory_make("fakesink", NULL);
2673 player->num_dynamic_pad--;
2678 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2679 LOGE("failed to autoplug for caps");
2683 gst_caps_unref(caps);
2688 /* execute new_element if created*/
2690 LOGD("adding new element to pipeline");
2692 /* set state to READY before add to bin */
2693 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2695 /* add new element to the pipeline */
2696 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2697 LOGE("failed to add autoplug element to bin");
2701 /* get pad from element */
2702 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2704 LOGE("failed to get sinkpad from autoplug element");
2709 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2710 LOGE("failed to link autoplug element");
2714 gst_object_unref(sinkpad);
2717 /* run. setting PLAYING here since streaming source is live source */
2718 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2722 gst_caps_unref(caps);
2728 STATE_CHANGE_FAILED:
2730 /* FIXIT : take care if new_element has already added to pipeline */
2732 gst_object_unref(GST_OBJECT(new_element));
2735 gst_object_unref(GST_OBJECT(sinkpad));
2738 gst_caps_unref(caps);
2740 /* FIXIT : how to inform this error to MSL ????? */
2741 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2742 * then post an error to application
2747 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2749 mmplayer_t *player = (mmplayer_t *)data;
2753 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2754 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2755 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2756 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2758 * [1] audio and video will be dumped with filesink.
2759 * [2] autoplugging is done by just using pad caps.
2760 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2761 * and the video will be dumped via filesink.
2763 if (player->num_dynamic_pad == 0) {
2764 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2766 if (!_mmplayer_gst_remove_fakesink(player,
2767 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2768 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2769 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2770 * source element are not same. To overcome this situation, this function will called
2771 * several places and several times. Therefore, this is not an error case.
2776 /* create dot before error-return. for debugging */
2777 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2779 player->no_more_pad = TRUE;
2785 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2787 GstElement *element = NULL;
2788 gchar *user_agent = NULL;
2789 MMHandleType attrs = 0;
2792 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2794 /* get profile attribute */
2795 attrs = MMPLAYER_GET_ATTRS(player);
2797 LOGE("failed to get content attribute");
2801 element = gst_element_factory_make("rtspsrc", "rtsp source");
2803 LOGE("failed to create rtspsrc element");
2808 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2810 SECURE_LOGD("user_agent : %s", user_agent);
2812 /* setting property to streaming source */
2813 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2815 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2817 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2818 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2819 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2820 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2826 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2828 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2830 mmplayer_t *player = (mmplayer_t *)data;
2831 MMHandleType attrs = 0;
2832 gchar *user_agent, *cookies, **cookie_list;
2833 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2834 user_agent = cookies = NULL;
2838 MMPLAYER_RETURN_IF_FAIL(player);
2840 LOGD("source element %s", GST_ELEMENT_NAME(source));
2842 attrs = MMPLAYER_GET_ATTRS(player);
2844 LOGE("failed to get content attribute");
2848 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2849 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2851 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2852 http_timeout = player->ini.http_timeout;
2854 SECURE_LOGD("cookies : %s", cookies);
2855 SECURE_LOGD("user_agent : %s", user_agent);
2856 LOGD("timeout : %d", http_timeout);
2858 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2860 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2861 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2862 g_strfreev(cookie_list);
2866 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2872 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2874 mmplayer_t *player = (mmplayer_t *)data;
2875 gchar *user_agent = NULL;
2876 MMHandleType attrs = 0;
2879 MMPLAYER_RETURN_IF_FAIL(player);
2881 attrs = MMPLAYER_GET_ATTRS(player);
2883 LOGE("failed to get content attribute");
2887 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2889 SECURE_LOGD("user_agent : %s", user_agent);
2892 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2898 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2900 mmplayer_t *player = (mmplayer_t *)data;
2901 GstElement *source = NULL;
2904 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2906 g_object_get(orig, pspec->name, &source, NULL);
2908 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2909 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2911 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2912 __mmplayer_http_src_setup(source, data);
2913 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2914 __mmplayer_rtsp_src_setup(source, data);
2915 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2916 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2917 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2918 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2919 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2921 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2922 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2923 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2924 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2926 gst_object_unref (source);
2932 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2933 GstStream * stream, gpointer data)
2935 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2936 GstStreamType stype = gst_stream_get_stream_type(stream);
2937 mmplayer_t *player = (mmplayer_t *)data;
2938 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2939 GstCaps *caps = gst_stream_get_caps(stream);
2940 gchar *caps_str = NULL;
2942 LOGD("Stream type %s flags 0x%x",
2943 gst_stream_type_get_name(stype),
2944 gst_stream_get_stream_flags(stream));
2945 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2948 caps_str = gst_caps_to_string(caps);
2949 LOGD(" caps: %s", caps_str);
2953 case GST_STREAM_TYPE_AUDIO:
2955 GstStructure *caps_structure = NULL;
2956 gint samplerate = 0;
2959 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2962 caps_structure = gst_caps_get_structure(caps, 0);
2963 gst_structure_get_int(caps_structure, "rate", &samplerate);
2964 gst_structure_get_int(caps_structure, "channels", &channels);
2966 if (channels > 0 && samplerate == 0) {
2967 LOGW("Skip corrupted audio stream");
2971 if (g_strrstr(caps_str, "mobile-xmf"))
2972 mm_player_set_attribute((MMHandleType)player, NULL,
2973 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2977 case GST_STREAM_TYPE_VIDEO:
2979 GstStructure *caps_structure = NULL;
2983 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2985 /* do not support multi track video */
2986 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2989 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2991 /* don't make video because of not required */
2992 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2993 (!player->set_mode.video_export)) {
2994 LOGD("no need video decoding, skip video stream");
2999 caps_structure = gst_caps_get_structure(caps, 0);
3000 gst_structure_get_int(caps_structure, "width", &width);
3003 if (player->v_stream_caps) {
3004 gst_caps_unref(player->v_stream_caps);
3005 player->v_stream_caps = NULL;
3008 player->v_stream_caps = gst_caps_copy(caps);
3009 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3014 case GST_STREAM_TYPE_TEXT:
3015 type = MM_PLAYER_TRACK_TYPE_TEXT;
3018 LOGW("Skip not supported stream type");
3022 _mmplayer_track_update_stream(player, type, stream);
3024 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3025 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3026 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3027 _mmplayer_set_audio_attrs(player, caps);
3034 gst_caps_unref(caps);
3036 LOGD("ret %d", ret);
3041 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3042 GstStream * stream, gpointer data)
3044 mmplayer_t *player = (mmplayer_t *)data;
3045 GstStreamType stype = gst_stream_get_stream_type(stream);
3048 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3050 LOGD("stream type %s", gst_stream_type_get_name(stype));
3052 /* public does not support audio hw decoder at the moment */
3054 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3055 LOGW("video decoder resource is already acquired, skip it.");
3059 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3060 LOGE("failed to acquire video decoder resource");
3063 player->interrupted_by_resource = FALSE;
3069 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3071 gchar *factory_name = NULL;
3072 mmplayer_t *player = (mmplayer_t *)data;
3073 mmplayer_gst_element_t *mainbin = NULL;
3076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3078 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3079 mainbin = player->pipeline->mainbin;
3081 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3082 factory_name, GST_ELEMENT_NAME(element));
3084 /* keep the first typefind reference only */
3085 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+
3086 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3087 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3089 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3090 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3091 LOGD("typefind reference is added");
3095 if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3096 /* update queue2 setting */
3097 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3098 gint64 dur_bytes = 0L;
3099 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3101 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3102 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3104 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3105 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3107 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3108 /* NOTE : in case of ts streaming, player could not get the correct duration info *
3109 * skip the pull mode(file or ring buffering) setting. */
3110 if (dur_bytes > 0) {
3111 if (!(__mmplayer_is_mpegts_type(player->type) || __mmplayer_is_hls_type(player->type)
3112 || __mmplayer_is_mp3_type(player->type))) {
3113 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3114 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3120 _mm_player_streaming_set_queue2(player->streamer,
3124 (guint64)dur_bytes); /* no meaning at the moment */
3128 /* update mq setting */
3129 if (g_strrstr(factory_name, "parsebin") && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3130 GstIterator *iter = NULL;
3131 GValue item = {0, };
3132 GstElement *ch_element = NULL;
3133 GstElementFactory *ch_factory = NULL;
3135 iter = gst_bin_iterate_recurse(child);
3137 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3138 ch_element = g_value_get_object(&item);
3139 ch_factory = gst_element_get_factory(ch_element);
3140 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3141 if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) {
3142 LOGD("get multiqueue");
3143 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3144 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3146 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3147 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3148 g_value_reset(&item);
3151 g_value_reset(&item);
3153 gst_iterator_free(iter);
3158 if (g_strrstr(factory_name, "parsebin")) {
3159 int video_codec_type = 0;
3160 int audio_codec_type = 0;
3162 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3163 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3164 if (player->type_caps &&
3165 !MMPLAYER_IS_HTTP_LIVE_STREAMING(player) &&
3166 !MMPLAYER_IS_DASH_STREAMING(player))
3167 g_object_set(G_OBJECT(element), "sink-caps", player->type_caps, NULL);
3169 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3170 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3172 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3173 and codec default type in ini has to be hw.
3175 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3176 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3177 g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL);
3178 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3179 g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL);
3181 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3182 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3183 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3184 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3186 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3187 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3189 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3190 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3192 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3193 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3196 _mmplayer_gst_element_added((GstElement *)child, element, data);
3202 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3204 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3209 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3211 GstElement *uridecodebin3 = NULL;
3214 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3216 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3217 if (!uridecodebin3) {
3218 LOGE("failed to create uridecodebin3");
3223 SECURE_LOGD("uri : %s", player->profile.uri);
3225 /* setting property to streaming source */
3226 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3227 "message-forward", TRUE,
3228 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3230 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3231 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3233 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3234 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3236 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3237 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3239 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3240 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3242 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3245 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3248 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3251 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3252 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3254 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3255 LOGW("[DASH] this is still experimental feature");
3258 return uridecodebin3;
3262 __mmplayer_gst_make_http_src(mmplayer_t *player)
3264 #define MAX_RETRY_COUNT 10
3265 GstElement *element = NULL;
3266 MMHandleType attrs = 0;
3267 gchar *user_agent, *cookies, **cookie_list;
3268 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3270 user_agent = cookies = NULL;
3274 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3276 /* get profile attribute */
3277 attrs = MMPLAYER_GET_ATTRS(player);
3279 LOGE("failed to get content attribute");
3283 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3285 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3287 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3292 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3293 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3295 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3296 http_timeout = player->ini.http_timeout;
3299 SECURE_LOGD("location : %s", player->profile.uri);
3300 SECURE_LOGD("cookies : %s", cookies);
3301 SECURE_LOGD("user_agent : %s", user_agent);
3302 LOGD("timeout : %d", http_timeout);
3304 /* setting property to streaming source */
3305 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3306 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3307 "retries", MAX_RETRY_COUNT, NULL);
3309 /* parsing cookies */
3310 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3311 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3312 g_strfreev(cookie_list);
3316 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3318 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3319 LOGW("[DASH] this is still experimental feature");
3326 __mmplayer_gst_make_file_src(mmplayer_t *player)
3328 GstElement *element = NULL;
3331 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3333 LOGD("using filesrc for 'file://' handler");
3334 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3335 LOGE("failed to get storage info");
3339 element = gst_element_factory_make("filesrc", "source");
3341 LOGE("failed to create filesrc");
3345 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3352 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3354 mmplayer_t *player = (mmplayer_t *)data;
3356 g_return_val_if_fail(player, FALSE);
3357 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3358 gst_message_ref(msg);
3360 g_mutex_lock(&player->bus_msg_q_lock);
3361 g_queue_push_tail(player->bus_msg_q, msg);
3362 g_mutex_unlock(&player->bus_msg_q_lock);
3364 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3365 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3366 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3370 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3372 mmplayer_t *player = (mmplayer_t *)(data);
3373 GstMessage *msg = NULL;
3376 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3378 player->pipeline->mainbin &&
3379 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3382 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3384 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3385 while (!player->bus_msg_thread_exit) {
3386 g_mutex_lock(&player->bus_msg_q_lock);
3387 msg = g_queue_pop_head(player->bus_msg_q);
3388 g_mutex_unlock(&player->bus_msg_q_lock);
3390 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3393 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3394 /* handle the gst msg */
3395 __mmplayer_gst_bus_msg_callback(msg, player);
3396 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3397 gst_message_unref(msg);
3400 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3407 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3409 gint64 dur_nsec = 0;
3412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3414 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3415 return MM_ERROR_NONE;
3417 /* NOTE : duration cannot be zero except live streaming.
3418 * Since some element could have some timing problem with querying duration, try again.
3420 if (player->duration == 0) {
3421 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3422 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3423 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3424 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3425 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3426 player->pending_seek.is_pending = true;
3427 player->pending_seek.pos = position;
3428 player->seek_state = MMPLAYER_SEEK_NONE;
3429 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3430 return MM_ERROR_PLAYER_NO_OP;
3432 player->seek_state = MMPLAYER_SEEK_NONE;
3433 return MM_ERROR_PLAYER_SEEK;
3436 player->duration = dur_nsec;
3439 if (player->duration > 0 && player->duration < position) {
3440 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3441 return MM_ERROR_INVALID_ARGUMENT;
3445 return MM_ERROR_NONE;
3449 __mmplayer_gst_check_seekable(mmplayer_t *player)
3451 GstQuery *query = NULL;
3452 gboolean seekable = FALSE;
3454 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3458 query = gst_query_new_seeking(GST_FORMAT_TIME);
3459 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3460 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3461 gst_query_unref(query);
3464 LOGW("non-seekable content");
3465 player->seek_state = MMPLAYER_SEEK_NONE;
3469 LOGW("failed to get seeking query");
3470 gst_query_unref(query); /* keep seeking operation */
3477 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3479 GstState element_state = GST_STATE_VOID_PENDING;
3480 GstState element_pending_state = GST_STATE_VOID_PENDING;
3481 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3485 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3486 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3488 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3491 ret = gst_element_set_state(element, state);
3492 if (ret == GST_STATE_CHANGE_FAILURE) {
3493 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3495 /* dump state of all element */
3496 _mmplayer_dump_pipeline_state(player);
3498 return MM_ERROR_PLAYER_INTERNAL;
3501 /* return here so state transition to be done in async mode */
3503 LOGD("async state transition. not waiting for state complete.");
3504 return MM_ERROR_NONE;
3507 /* wait for state transition */
3508 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3509 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3510 LOGE("failed to change [%s] element state to [%s] within %d sec",
3511 GST_ELEMENT_NAME(element),
3512 gst_element_state_get_name(state), timeout);
3514 LOGE(" [%s] state : %s pending : %s",
3515 GST_ELEMENT_NAME(element),
3516 gst_element_state_get_name(element_state),
3517 gst_element_state_get_name(element_pending_state));
3519 /* dump state of all element */
3520 _mmplayer_dump_pipeline_state(player);
3522 return MM_ERROR_PLAYER_INTERNAL;
3525 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3529 return MM_ERROR_NONE;
3533 _mmplayer_gst_start(mmplayer_t *player)
3535 int ret = MM_ERROR_NONE;
3536 gboolean async = FALSE;
3540 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3542 /* NOTE : if SetPosition was called before Start. do it now
3543 * streaming doesn't support it. so it should be always sync
3544 * !!create one more api to check if there is pending seek rather than checking variables
3546 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3547 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3548 ret = _mmplayer_gst_pause(player, FALSE);
3549 if (ret != MM_ERROR_NONE) {
3550 LOGE("failed to set state to PAUSED for pending seek");
3554 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3555 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3556 LOGW("failed to seek pending position. starting from the begin of content");
3559 LOGD("current state before doing transition");
3560 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3561 MMPLAYER_PRINT_STATE(player);
3563 /* set pipeline state to PLAYING */
3564 ret = _mmplayer_gst_set_state(player,
3565 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3566 if (ret != MM_ERROR_NONE) {
3567 LOGE("failed to set state to PLAYING");
3571 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3573 /* generating debug info before returning error */
3574 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3582 _mmplayer_gst_stop(mmplayer_t *player)
3584 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3585 MMHandleType attrs = 0;
3586 gboolean rewind = FALSE;
3588 int ret = MM_ERROR_NONE;
3592 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3593 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3595 LOGD("current state before doing transition");
3596 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3597 MMPLAYER_PRINT_STATE(player);
3599 attrs = MMPLAYER_GET_ATTRS(player);
3601 LOGE("cannot get content attribute");
3602 return MM_ERROR_PLAYER_INTERNAL;
3605 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3606 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3608 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3609 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3612 if (player->es_player_push_mode)
3613 /* disable the async state transition because there could be no data in the pipeline */
3614 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3617 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3619 if (player->es_player_push_mode) {
3620 /* enable the async state transition as default operation */
3621 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3624 /* return if set_state has failed */
3625 if (ret != MM_ERROR_NONE) {
3626 LOGE("failed to set state.");
3632 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3633 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3634 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3635 LOGW("failed to rewind");
3636 ret = MM_ERROR_PLAYER_SEEK;
3641 player->sent_bos = FALSE;
3643 if (player->es_player_push_mode) //for cloudgame
3646 /* wait for seek to complete */
3647 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3648 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3649 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3651 LOGE("fail to stop player.");
3652 ret = MM_ERROR_PLAYER_INTERNAL;
3653 _mmplayer_dump_pipeline_state(player);
3656 /* generate dot file if enabled */
3657 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3665 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3667 int ret = MM_ERROR_NONE;
3671 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3672 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3674 LOGD("current state before doing transition");
3675 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3676 MMPLAYER_PRINT_STATE(player);
3678 /* set pipeline status to PAUSED */
3679 ret = _mmplayer_gst_set_state(player,
3680 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3685 if (ret != MM_ERROR_NONE) {
3686 GstMessage *msg = NULL;
3687 GTimer *timer = NULL;
3688 gdouble MAX_TIMEOUT_SEC = 3;
3690 LOGE("failed to set state to PAUSED");
3692 if (!player->bus_watcher) {
3693 LOGE("there is no bus msg thread. pipeline is shutting down.");
3697 if (player->msg_posted) {
3698 LOGE("error msg is already posted.");
3702 timer = g_timer_new();
3703 g_timer_start(timer);
3705 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3708 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3710 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3711 GError *error = NULL;
3713 /* parse error code */
3714 gst_message_parse_error(msg, &error, NULL);
3716 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3717 /* Note : the streaming error from the streaming source is handled
3718 * using __mmplayer_handle_streaming_error.
3720 __mmplayer_handle_streaming_error(player, msg);
3723 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3725 if (error->domain == GST_STREAM_ERROR)
3726 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3727 else if (error->domain == GST_RESOURCE_ERROR)
3728 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3729 else if (error->domain == GST_LIBRARY_ERROR)
3730 ret = __mmplayer_gst_handle_library_error(player, error->code);
3731 else if (error->domain == GST_CORE_ERROR)
3732 ret = __mmplayer_gst_handle_core_error(player, error->code);
3734 g_error_free(error);
3736 player->msg_posted = TRUE;
3738 gst_message_unref(msg);
3740 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3742 gst_object_unref(bus);
3743 g_timer_stop(timer);
3744 g_timer_destroy(timer);
3749 if (MMPLAYER_USE_DECODEBIN(player)) {
3750 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3751 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3752 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3755 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3758 /* generate dot file before returning error */
3759 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3767 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3769 int ret = MM_ERROR_NONE;
3774 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3775 MM_ERROR_PLAYER_NOT_INITIALIZED);
3777 LOGD("current state before doing transition");
3778 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3779 MMPLAYER_PRINT_STATE(player);
3782 LOGD("do async state transition to PLAYING");
3784 /* set pipeline state to PLAYING */
3785 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3787 ret = _mmplayer_gst_set_state(player,
3788 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3789 if (ret != MM_ERROR_NONE) {
3790 LOGE("failed to set state to PLAYING");
3795 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3798 /* generate dot file */
3799 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3806 /* sending event to one of sinkelements */
3808 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3810 GstEvent *event2 = NULL;
3811 GList *sinks = NULL;
3812 gboolean res = FALSE;
3815 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3816 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3818 /* While adding subtitles in live feeds seek is getting called.
3819 Adding defensive check in framework layer.*/
3820 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3821 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3822 LOGE("Should not send seek event during live playback");
3827 if (player->play_subtitle)
3828 event2 = gst_event_copy((const GstEvent *)event);
3830 sinks = player->sink_elements;
3832 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3834 if (GST_IS_ELEMENT(sink)) {
3835 /* keep ref to the event */
3836 gst_event_ref(event);
3838 if ((res = gst_element_send_event(sink, event))) {
3839 LOGD("sending event[%s] to sink element [%s] success!",
3840 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3842 /* rtsp case, async_done is not called after seek during pause state */
3843 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3844 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3845 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3846 LOGD("RTSP seek completed, after pause state..");
3847 player->seek_state = MMPLAYER_SEEK_NONE;
3848 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3854 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3855 sinks = g_list_next(sinks);
3862 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3863 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3866 sinks = g_list_next(sinks);
3869 /* Note : Textbin is not linked to the video or audio bin.
3870 * It needs to send the event to the text sink seperately.
3872 if (player->play_subtitle && player->pipeline) {
3873 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3875 if (GST_IS_ELEMENT(text_sink)) {
3876 /* keep ref to the event */
3877 gst_event_ref(event2);
3879 if ((res = gst_element_send_event(text_sink, event2)))
3880 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3881 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3883 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3884 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3886 gst_event_unref(event2);
3890 gst_event_unref(event);
3898 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3899 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3900 gint64 cur, GstSeekType stop_type, gint64 stop)
3902 GstEvent *event = NULL;
3903 gboolean result = FALSE;
3907 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3909 if (player->pipeline && player->pipeline->textbin)
3910 __mmplayer_drop_subtitle(player, FALSE);
3912 event = gst_event_new_seek(rate, format, flags, cur_type,
3913 cur, stop_type, stop);
3915 result = _mmplayer_gst_send_event_to_sink(player, event);
3923 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3925 int ret = MM_ERROR_NONE;
3926 gint64 pos_nsec = 0;
3927 gboolean accurate = FALSE;
3928 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3931 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3932 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3934 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3935 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3938 ret = __mmplayer_gst_check_duration(player, position);
3939 if (ret != MM_ERROR_NONE) {
3940 LOGE("failed to check duration 0x%X", ret);
3941 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3944 if (!__mmplayer_gst_check_seekable(player))
3945 return MM_ERROR_PLAYER_NO_OP;
3947 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3948 position, player->playback_rate, player->duration);
3950 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3951 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3952 This causes problem is position calculation during normal pause resume scenarios also.
3953 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3954 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3955 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3956 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3957 LOGW("getting current position failed in seek");
3959 player->last_position = pos_nsec;
3960 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3963 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3964 LOGD("not completed seek");
3965 return MM_ERROR_PLAYER_DOING_SEEK;
3968 if (!internal_called)
3969 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3971 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3972 that's why set position through property. */
3973 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3974 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3975 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3976 (!player->videodec_linked) && (!player->audiodec_linked)) {
3978 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3979 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3981 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3982 player->seek_state = MMPLAYER_SEEK_NONE;
3983 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3985 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3987 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3989 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3991 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3992 GST_FORMAT_TIME, seek_flags,
3993 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3994 LOGE("failed to set position");
3999 /* NOTE : store last seeking point to overcome some bad operation
4000 * (returning zero when getting current position) of some elements
4002 player->last_position = position;
4004 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4005 if (player->playback_rate > 1.0)
4006 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4008 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4009 LOGD("buffering should be reset after seeking");
4010 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4011 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4015 return MM_ERROR_NONE;
4018 player->pending_seek.is_pending = true;
4019 player->pending_seek.pos = position;
4021 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4022 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4023 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4024 player->pending_seek.pos);
4026 return MM_ERROR_NONE;
4029 player->seek_state = MMPLAYER_SEEK_NONE;
4030 return MM_ERROR_PLAYER_SEEK;
4034 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4036 #define TRICKPLAY_OFFSET GST_MSECOND
4038 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4039 gint64 pos_nsec = 0;
4040 gboolean ret = TRUE;
4042 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4043 MM_ERROR_PLAYER_NOT_INITIALIZED);
4045 current_state = MMPLAYER_CURRENT_STATE(player);
4047 /* NOTE : query position except paused state to overcome some bad operation
4048 * please refer to below comments in details
4050 if (current_state != MM_PLAYER_STATE_PAUSED)
4051 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4053 /* NOTE : get last point to overcome some bad operation of some elements
4054 *(returning zero when getting current position in paused state
4055 * and when failed to get position during seeking
4057 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4058 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4060 if (player->playback_rate < 0.0)
4061 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4063 pos_nsec = player->last_position;
4066 pos_nsec = player->last_position;
4068 player->last_position = pos_nsec;
4070 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4073 if (player->duration > 0 && pos_nsec > player->duration)
4074 pos_nsec = player->duration;
4076 player->last_position = pos_nsec;
4079 *position = pos_nsec;
4081 return MM_ERROR_NONE;
4085 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4087 #define STREAMING_IS_FINISHED 0
4088 #define BUFFERING_MAX_PER 100
4089 #define DEFAULT_PER_VALUE -1
4090 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4092 mmplayer_gst_element_t *mainbin = NULL;
4093 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4094 gint64 buffered_total = 0;
4095 gint64 position = 0;
4096 gint buffered_sec = -1;
4097 GstBufferingMode mode = GST_BUFFERING_STREAM;
4098 gint64 content_size_time = player->duration;
4099 guint64 content_size_bytes = player->http_content_size;
4101 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4103 player->pipeline->mainbin,
4104 MM_ERROR_PLAYER_NOT_INITIALIZED);
4106 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4111 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4112 /* and rtsp is not ready yet. */
4113 LOGW("it's only used for http streaming case");
4114 return MM_ERROR_PLAYER_NO_OP;
4117 if (content_size_time <= 0 || content_size_bytes <= 0) {
4118 LOGW("there is no content size");
4119 return MM_ERROR_NONE;
4122 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4123 LOGW("fail to get current position");
4124 return MM_ERROR_NONE;
4127 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4128 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4130 mainbin = player->pipeline->mainbin;
4131 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4133 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4134 GstQuery *query = NULL;
4135 gint byte_in_rate = 0, byte_out_rate = 0;
4136 gint64 estimated_total = 0;
4138 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4139 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4140 LOGW("fail to get buffering query from queue2");
4142 gst_query_unref(query);
4143 return MM_ERROR_NONE;
4146 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4147 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4149 if (mode == GST_BUFFERING_STREAM) {
4150 /* using only queue in case of push mode(ts / mp3) */
4151 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4152 GST_FORMAT_BYTES, &buffered_total)) {
4153 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4154 end_per = 100 * buffered_total / content_size_bytes;
4157 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4159 guint num_of_ranges = 0;
4160 gint64 start_byte = 0, stop_byte = 0;
4162 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4163 if (estimated_total != STREAMING_IS_FINISHED) {
4164 /* buffered size info from queue2 */
4165 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4166 for (idx = 0; idx < num_of_ranges; idx++) {
4167 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4168 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4170 buffered_total += (stop_byte - start_byte);
4173 end_per = BUFFERING_MAX_PER;
4176 gst_query_unref(query);
4179 if (end_per == DEFAULT_PER_VALUE) {
4180 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4182 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4184 /* buffered size info from multiqueue */
4185 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4186 guint curr_size_bytes = 0;
4187 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4188 "curr-size-bytes", &curr_size_bytes, NULL);
4189 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4190 buffered_total += curr_size_bytes;
4193 if (avg_byterate > 0)
4194 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4195 else if (player->total_maximum_bitrate > 0)
4196 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4197 else if (player->total_bitrate > 0)
4198 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4200 if (buffered_sec >= 0)
4201 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4205 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4206 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4208 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4209 buffered_total, buffered_sec, *start_pos, *end_pos);
4211 return MM_ERROR_NONE;
4215 _mmplayer_gst_create_source(mmplayer_t *player)
4217 GstElement *element = NULL;
4220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4221 player->pipeline->mainbin, NULL);
4223 /* setup source for gapless play */
4224 switch (player->profile.uri_type) {
4226 case MM_PLAYER_URI_TYPE_FILE:
4227 element = __mmplayer_gst_make_file_src(player);
4229 case MM_PLAYER_URI_TYPE_URL_HTTP:
4230 element = __mmplayer_gst_make_http_src(player);
4233 LOGE("not support uri type %d", player->profile.uri_type);
4238 LOGE("failed to create source element");
4247 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4250 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4251 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4253 SECURE_LOGD("uri : %s", player->profile.uri);
4255 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4257 if ((player->v_stream_caps) &&
4258 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4259 return MM_ERROR_PLAYER_INTERNAL;
4261 if ((player->a_stream_caps) &&
4262 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4263 return MM_ERROR_PLAYER_INTERNAL;
4265 if ((player->s_stream_caps) &&
4266 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4267 return MM_ERROR_PLAYER_INTERNAL;
4270 return MM_ERROR_NONE;
4274 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4276 mmplayer_gst_element_t *mainbin = NULL;
4277 GstElement *autoplug_elem = NULL;
4280 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4281 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4283 mainbin = player->pipeline->mainbin;
4285 LOGD("uri type %d", player->profile.uri_type);
4287 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4288 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4289 return MM_ERROR_PLAYER_INTERNAL;
4292 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4293 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4296 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4297 if (!autoplug_elem) {
4298 LOGE("failed to create uridecodebin3 element");
4302 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4303 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4304 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4306 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4307 LOGE("failed to add uridecodebin to pipeline");
4311 /* FIXME: required ?*/
4312 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4313 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4314 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4316 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4317 LOGE("failed to create fakesink");
4320 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4322 /* take ownership of fakesink. we are reusing it */
4323 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4325 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4326 LOGE("failed to add fakesink to bin");
4327 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4332 return MM_ERROR_NONE;
4336 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4337 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4339 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4340 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4342 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4343 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4345 return MM_ERROR_PLAYER_INTERNAL;
4349 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4351 mmplayer_gst_element_t *mainbin = NULL;
4352 GstElement *src_elem = NULL;
4353 GstElement *autoplug_elem = NULL;
4354 GList *element_bucket = NULL;
4355 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4358 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4359 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4361 LOGD("uri type %d", player->profile.uri_type);
4363 /* create source element */
4364 switch (player->profile.uri_type) {
4365 case MM_PLAYER_URI_TYPE_URL_RTSP:
4366 src_elem = __mmplayer_gst_make_rtsp_src(player);
4368 case MM_PLAYER_URI_TYPE_URL_HTTP:
4369 src_elem = __mmplayer_gst_make_http_src(player);
4371 case MM_PLAYER_URI_TYPE_FILE:
4372 src_elem = __mmplayer_gst_make_file_src(player);
4374 case MM_PLAYER_URI_TYPE_SS:
4376 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4377 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4379 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4383 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4384 LOGD("get timeout from ini");
4385 http_timeout = player->ini.http_timeout;
4388 /* setting property to streaming source */
4389 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4392 case MM_PLAYER_URI_TYPE_MEM:
4394 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4396 src_elem = gst_element_factory_make("appsrc", "mem-source");
4398 LOGE("failed to create appsrc element");
4402 g_object_set(src_elem, "stream-type", stream_type,
4403 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4405 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4406 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4407 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4408 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4412 LOGE("not support uri type");
4417 LOGE("failed to create source element");
4418 return MM_ERROR_PLAYER_INTERNAL;
4421 mainbin = player->pipeline->mainbin;
4423 /* take source element */
4424 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4426 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4427 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4428 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4430 /* create next element for auto-plugging */
4431 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4432 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4433 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4434 if (!autoplug_elem) {
4435 LOGE("failed to create typefind element");
4439 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4440 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4441 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4442 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4443 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4444 if (!autoplug_elem) {
4445 LOGE("failed to create decodebin");
4449 /* default size of mq in decodebin is 2M
4450 * but it can cause blocking issue during seeking depends on content. */
4451 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4454 if (autoplug_elem) {
4455 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4456 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4457 mainbin[autoplug_elem_id].gst = autoplug_elem;
4459 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4462 /* add elements to pipeline */
4463 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4464 LOGE("failed to add elements to pipeline");
4468 /* linking elements in the bucket by added order. */
4469 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4470 LOGE("failed to link some elements");
4474 /* FIXME: need to check whether this is required or not. */
4475 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4476 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4477 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4478 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4479 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4481 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4482 LOGE("failed to create fakesink");
4485 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4487 /* take ownership of fakesink. we are reusing it */
4488 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4490 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4491 LOGE("failed to add fakesink to bin");
4492 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4497 g_list_free(element_bucket);
4500 return MM_ERROR_NONE;
4503 g_list_free(element_bucket);
4505 if (mainbin[MMPLAYER_M_SRC].gst)
4506 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4508 if (mainbin[autoplug_elem_id].gst)
4509 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4511 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4512 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4514 mainbin[MMPLAYER_M_SRC].gst = NULL;
4515 mainbin[autoplug_elem_id].gst = NULL;
4516 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4518 return MM_ERROR_PLAYER_INTERNAL;
4522 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4525 mmplayer_gst_element_t *mainbin = NULL;
4528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4529 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4531 mainbin = player->pipeline->mainbin;
4533 /* connect bus callback */
4534 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4536 LOGE("cannot get bus from pipeline");
4537 return MM_ERROR_PLAYER_INTERNAL;
4540 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4541 (GstBusFunc)__mmplayer_gst_msg_push, player,
4542 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4543 if (player->bus_watcher == 0) {
4544 LOGE("failed to add bus watch");
4545 return MM_ERROR_PLAYER_INTERNAL;
4548 g_mutex_init(&player->bus_watcher_mutex);
4549 g_cond_init(&player->bus_watcher_cond);
4551 player->context.thread_default = g_main_context_get_thread_default();
4552 if (player->context.thread_default == NULL) {
4553 player->context.thread_default = g_main_context_default();
4554 LOGD("thread-default context is the global default context");
4556 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4558 /* set sync handler to get tag synchronously */
4559 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4560 gst_object_unref(GST_OBJECT(bus));
4562 /* create gst bus_msb_cb thread */
4563 g_mutex_init(&player->bus_msg_thread_mutex);
4564 g_cond_init(&player->bus_msg_thread_cond);
4565 player->bus_msg_thread_exit = FALSE;
4566 player->bus_msg_thread =
4567 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4568 if (!player->bus_msg_thread) {
4569 LOGE("failed to create gst BUS msg thread");
4570 g_mutex_clear(&player->bus_msg_thread_mutex);
4571 g_cond_clear(&player->bus_msg_thread_cond);
4572 return MM_ERROR_PLAYER_INTERNAL;
4576 return MM_ERROR_NONE;
4580 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4582 int ret = MM_ERROR_NONE;
4583 mmplayer_gst_element_t *mainbin = NULL;
4584 MMMessageParamType msg_param = {0,};
4585 GstElement *element = NULL;
4586 MMHandleType attrs = 0;
4588 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4592 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4593 LOGE("player is not initialized");
4597 mainbin = player->pipeline->mainbin;
4598 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4600 attrs = MMPLAYER_GET_ATTRS(player);
4602 LOGE("fail to get attributes");
4606 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4608 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4609 LOGE("failed to parse profile");
4610 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4614 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4615 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4616 LOGE("dash or hls is not supportable");
4617 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4621 if (!MMPLAYER_USE_DECODEBIN(player)) {
4622 ret = _mmplayer_gst_build_pipeline_with_src(player);
4623 if (ret != MM_ERROR_NONE)
4626 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4627 LOGE("Failed to change state of uridecodebin3 element");
4633 element = _mmplayer_gst_create_source(player);
4635 LOGE("no source element was created");
4639 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4640 LOGE("failed to add source element to pipeline");
4641 gst_object_unref(GST_OBJECT(element));
4646 /* take source element */
4647 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4648 mainbin[MMPLAYER_M_SRC].gst = element;
4652 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4653 if (player->streamer == NULL) {
4654 player->streamer = _mm_player_streaming_create();
4655 _mm_player_streaming_initialize(player->streamer, TRUE);
4658 elem_idx = MMPLAYER_M_TYPEFIND;
4659 element = gst_element_factory_make("typefind", "typefinder");
4660 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4661 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4663 elem_idx = MMPLAYER_M_AUTOPLUG;
4664 element = _mmplayer_gst_make_decodebin(player);
4667 /* check autoplug element is OK */
4669 LOGE("can not create element(%d)", elem_idx);
4673 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4674 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4675 gst_object_unref(GST_OBJECT(element));
4680 mainbin[elem_idx].id = elem_idx;
4681 mainbin[elem_idx].gst = element;
4683 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4684 LOGE("Failed to link src - autoplug(or typefind)");
4688 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4689 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4690 LOGE("Failed to change state of src element");
4694 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4695 LOGE("Failed to change state of decodebin");
4700 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4701 LOGE("Failed to change state of src element");
4706 player->gapless.stream_changed = TRUE;
4707 player->gapless.running = TRUE;
4713 _mmplayer_set_reconfigure_state(player, FALSE);
4714 if (!player->msg_posted) {
4715 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4716 player->msg_posted = TRUE;