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 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
58 /* check whether the error is posted from not-activated track or not */
60 gint active_index = 0;
62 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
64 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
65 LOGD("current active pad index -%d", active_index);
67 if (src_element_name) {
70 if (player->audio_decoders) {
71 GList *adec = player->audio_decoders;
72 for (; adec ; adec = g_list_next(adec)) {
73 gchar *name = adec->data;
75 LOGD("found audio decoder name = %s", name);
76 if (g_strrstr(name, src_element_name)) {
83 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
86 if (active_index != msg_src_pos) {
87 LOGD("skip error because error is posted from no activated track");
95 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
97 /* Demuxer can't parse one track because it's corrupted.
98 * So, the decoder for it is not linked.
99 * But, it has one playable track.
101 if (g_strrstr(klass, "Demux")) {
102 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
103 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
104 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
105 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
107 if (player->pipeline->audiobin) { // PCM
108 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
110 LOGD("not found any available codec. Player should be destroyed.");
111 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
116 return MM_ERROR_PLAYER_INVALID_STREAM;
120 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
122 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
123 LOGE("Not supported subtitle.");
124 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
126 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
130 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
132 /* Decoder Custom Message */
133 if (!strstr(error->message, "ongoing"))
134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
136 if (strncasecmp(klass, "audio", 5)) {
137 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
138 LOGD("Video can keep playing.");
139 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
141 } else if (strncasecmp(klass, "video", 5)) {
142 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
143 LOGD("Audio can keep playing.");
144 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
148 LOGD("not found any available codec. Player should be destroyed.");
149 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
153 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
155 if (strstr(error->message, "rights expired"))
156 return MM_ERROR_PLAYER_DRM_EXPIRED;
157 else if (strstr(error->message, "no rights"))
158 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
159 else if (strstr(error->message, "has future rights"))
160 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
161 else if (strstr(error->message, "opl violation"))
162 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
164 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
167 /* NOTE : decide gstreamer state whether there is some playable track or not. */
169 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
171 gchar *src_element_name = NULL;
172 GstElement *src_element = NULL;
173 GstElementFactory *factory = NULL;
174 const gchar *klass = NULL;
178 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
179 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
180 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
181 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
183 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
185 src_element = GST_ELEMENT_CAST(message->src);
186 src_element_name = GST_ELEMENT_NAME(src_element);
187 if (!src_element_name)
188 return MM_ERROR_PLAYER_INTERNAL;
190 factory = gst_element_get_factory(src_element);
192 return MM_ERROR_PLAYER_INTERNAL;
194 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
196 return MM_ERROR_PLAYER_INTERNAL;
198 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
199 error->code, error->message, src_element_name, klass);
201 if (MMPLAYER_USE_DECODEBIN(player) &&
202 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
203 return MM_ERROR_NONE;
205 switch (error->code) {
206 case GST_STREAM_ERROR_DECODE:
207 return __mmplayer_gst_transform_error_decode(player, klass);
208 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
209 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
210 case GST_STREAM_ERROR_WRONG_TYPE:
211 return __mmplayer_gst_transform_error_type(player, src_element);
212 case GST_STREAM_ERROR_FAILED:
213 return __mmplayer_gst_transform_error_failed(player, klass, error);
214 case GST_STREAM_ERROR_DECRYPT:
215 case GST_STREAM_ERROR_DECRYPT_NOKEY:
216 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
217 return __mmplayer_gst_transform_error_decrypt(player, error);
224 return MM_ERROR_PLAYER_INVALID_STREAM;
228 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
230 gint trans_err = MM_ERROR_NONE;
234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 case GST_CORE_ERROR_MISSING_PLUGIN:
238 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
239 case GST_CORE_ERROR_STATE_CHANGE:
240 case GST_CORE_ERROR_SEEK:
241 case GST_CORE_ERROR_NOT_IMPLEMENTED:
242 case GST_CORE_ERROR_FAILED:
243 case GST_CORE_ERROR_TOO_LAZY:
244 case GST_CORE_ERROR_PAD:
245 case GST_CORE_ERROR_THREAD:
246 case GST_CORE_ERROR_NEGOTIATION:
247 case GST_CORE_ERROR_EVENT:
248 case GST_CORE_ERROR_CAPS:
249 case GST_CORE_ERROR_TAG:
250 case GST_CORE_ERROR_CLOCK:
251 case GST_CORE_ERROR_DISABLED:
253 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
263 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
265 gint trans_err = MM_ERROR_NONE;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
272 case GST_LIBRARY_ERROR_FAILED:
273 case GST_LIBRARY_ERROR_TOO_LAZY:
274 case GST_LIBRARY_ERROR_INIT:
275 case GST_LIBRARY_ERROR_SHUTDOWN:
276 case GST_LIBRARY_ERROR_SETTINGS:
277 case GST_LIBRARY_ERROR_ENCODE:
279 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
289 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
291 gint trans_err = MM_ERROR_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
298 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
299 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
301 case GST_RESOURCE_ERROR_NOT_FOUND:
302 case GST_RESOURCE_ERROR_OPEN_READ:
303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
304 || MMPLAYER_IS_RTSP_STREAMING(player)) {
305 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
308 case GST_RESOURCE_ERROR_READ:
309 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
310 || MMPLAYER_IS_RTSP_STREAMING(player)) {
311 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
313 } else if (message != NULL && message->src != NULL) {
314 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
315 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
317 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
318 path_type = MMPLAYER_PATH_VOD;
319 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
320 path_type = MMPLAYER_PATH_TEXT;
322 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
323 /* check storage state */
324 storage_get_state(player->storage_info[path_type].id, &storage_state);
325 player->storage_info[path_type].state = storage_state;
326 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
329 case GST_RESOURCE_ERROR_WRITE:
330 case GST_RESOURCE_ERROR_FAILED:
331 case GST_RESOURCE_ERROR_SEEK:
332 case GST_RESOURCE_ERROR_TOO_LAZY:
333 case GST_RESOURCE_ERROR_BUSY:
334 case GST_RESOURCE_ERROR_OPEN_WRITE:
335 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
336 case GST_RESOURCE_ERROR_CLOSE:
337 case GST_RESOURCE_ERROR_SYNC:
338 case GST_RESOURCE_ERROR_SETTINGS:
340 trans_err = MM_ERROR_PLAYER_INTERNAL;
350 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
352 gint trans_err = MM_ERROR_NONE;
356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
358 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
360 switch (error->code) {
361 case GST_STREAM_ERROR_FAILED:
362 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
363 case GST_STREAM_ERROR_DECODE:
364 case GST_STREAM_ERROR_WRONG_TYPE:
365 case GST_STREAM_ERROR_DECRYPT:
366 case GST_STREAM_ERROR_DECRYPT_NOKEY:
367 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
368 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
371 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
372 case GST_STREAM_ERROR_TOO_LAZY:
373 case GST_STREAM_ERROR_ENCODE:
374 case GST_STREAM_ERROR_DEMUX:
375 case GST_STREAM_ERROR_MUX:
376 case GST_STREAM_ERROR_FORMAT:
378 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
388 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
390 MMMessageParamType msg_param;
391 gchar *msg_src_element;
395 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
396 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
398 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
400 memset(&msg_param, 0, sizeof(MMMessageParamType));
402 if (error->domain == GST_CORE_ERROR) {
403 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
404 } else if (error->domain == GST_LIBRARY_ERROR) {
405 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
406 } else if (error->domain == GST_RESOURCE_ERROR) {
407 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
408 } else if (error->domain == GST_STREAM_ERROR) {
409 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
411 LOGW("This error domain is not defined.");
413 /* we treat system error as an internal error */
414 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
418 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
420 msg_param.data = (void *)error->message;
422 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
423 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
427 if (msg_param.code == MM_ERROR_NONE)
430 /* skip error to avoid duplicated posting */
431 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
432 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
433 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
434 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
436 /* The error will be handled by mused.
437 * @ref _mmplayer_manage_external_storage_state() */
439 LOGW("storage is removed, skip error post");
443 /* post error to application */
444 if (!player->msg_posted) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
446 /* don't post more if one was sent already */
447 player->msg_posted = TRUE;
449 LOGD("skip error post because it's sent already.");
458 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
461 MMMessageParamType msg_param = {0, };
462 gchar *msg_src_element = NULL;
466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
467 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
468 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
470 switch (error->code) {
471 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
472 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
474 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
475 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
477 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
478 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
480 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
481 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
483 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
484 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
486 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
487 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
489 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
490 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
492 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
493 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
495 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
498 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
501 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
504 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
507 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
510 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
513 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
516 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
519 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
522 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
525 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
528 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
531 case MMPLAYER_STREAMING_ERROR_GONE:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
534 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
540 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
543 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
546 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
549 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
552 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
555 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
558 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
561 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
564 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
567 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
570 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
573 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
576 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
579 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
582 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
585 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
588 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
591 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
594 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
597 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
600 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
603 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
608 return MM_ERROR_PLAYER_STREAMING_FAIL;
613 msg_param.data = (void *)(error->message);
616 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
618 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
619 msg_src_element, msg_param.code, (char *)msg_param.data);
622 /* post error to application */
623 if (!player->msg_posted) {
624 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
626 /* don't post more if one was sent already */
627 player->msg_posted = TRUE;
629 LOGD("skip error post because it's sent already.");
638 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
640 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
641 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
642 gst_tag_list_get_string(tags, "stitching_software",
643 &metadata->stitching_software);
644 gst_tag_list_get_string(tags, "projection_type",
645 &metadata->projection_type_string);
646 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
647 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
648 gst_tag_list_get_int(tags, "init_view_heading",
649 &metadata->init_view_heading);
650 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
651 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
652 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
653 gst_tag_list_get_int(tags, "full_pano_width_pixels",
654 &metadata->full_pano_width_pixels);
655 gst_tag_list_get_int(tags, "full_pano_height_pixels",
656 &metadata->full_pano_height_pixels);
657 gst_tag_list_get_int(tags, "cropped_area_image_width",
658 &metadata->cropped_area_image_width);
659 gst_tag_list_get_int(tags, "cropped_area_image_height",
660 &metadata->cropped_area_image_height);
661 gst_tag_list_get_int(tags, "cropped_area_left",
662 &metadata->cropped_area_left);
663 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
664 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
665 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
666 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
670 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
673 /* macro for better code readability */
674 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
676 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
677 if (string != NULL) { \
678 SECURE_LOGD("update tag string : %s", string); \
679 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
680 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
681 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
682 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
683 mm_player_set_attribute((MMHandleType)player, NULL,\
684 playertag, new_string, strlen(new_string), NULL); \
685 MMPLAYER_FREEIF(new_string); \
687 mm_player_set_attribute((MMHandleType)player, NULL,\
688 playertag, string, strlen(string), NULL); \
690 MMPLAYER_FREEIF(string); \
695 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
697 GstSample *sample = NULL;\
698 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
699 GstMapInfo info = GST_MAP_INFO_INIT;\
700 buffer = gst_sample_get_buffer(sample);\
701 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
702 LOGD("failed to get image data from tag");\
703 gst_sample_unref(sample);\
706 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
707 MMPLAYER_FREEIF(player->album_art);\
708 player->album_art = (gchar *)g_malloc(info.size);\
709 if (player->album_art) {\
710 memcpy(player->album_art, info.data, info.size);\
711 mm_player_set_attribute((MMHandleType)player, NULL,\
712 playertag, (void *)player->album_art, info.size, NULL); \
713 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
714 msg_param.data = (void *)player->album_art;\
715 msg_param.size = info.size;\
716 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
717 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
720 gst_buffer_unmap(buffer, &info);\
721 gst_sample_unref(sample);\
725 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
730 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
731 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
732 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
733 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
734 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
736 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
737 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
738 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
739 mm_player_set_attribute((MMHandleType)player, NULL,\
740 "content_audio_bitrate", v_uint, NULL); \
741 player->bitrate[track_type] = v_uint; \
742 player->total_bitrate = 0; \
743 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
744 player->total_bitrate += player->bitrate[i]; \
745 mm_player_set_attribute((MMHandleType)player, NULL,\
746 playertag, player->total_bitrate, NULL); \
747 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
748 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
749 player->maximum_bitrate[track_type] = v_uint; \
750 player->total_maximum_bitrate = 0; \
751 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
752 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, player->total_maximum_bitrate, NULL); \
755 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
757 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
764 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
766 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
768 string = g_strdup_printf("%d", g_date_get_year(date));\
769 mm_player_set_attribute((MMHandleType)player, NULL,\
770 playertag, string, strlen(string), NULL); \
771 SECURE_LOGD("metainfo year : %s", string);\
772 MMPLAYER_FREEIF(string);\
778 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
780 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
781 if (datetime != NULL) {\
782 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, string, strlen(string), NULL); \
785 SECURE_LOGD("metainfo year : %s", string);\
786 MMPLAYER_FREEIF(string);\
787 gst_date_time_unref(datetime);\
793 GstTagList *tag_list = NULL;
798 GstDateTime *datetime = NULL;
800 GstBuffer *buffer = NULL;
802 MMMessageParamType msg_param = {0, };
804 /* currently not used. but those are needed for above macro */
805 //guint64 v_uint64 = 0;
806 //gdouble v_double = 0;
808 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
810 /* get tag list from gst message */
811 gst_message_parse_tag(msg, &tag_list);
813 /* store tags to player attributes */
814 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
815 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
816 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
817 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
818 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
819 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
821 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
823 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
827 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
828 MMPLAYER_UPDATE_TAG_LOCK(player);
829 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
830 MMPLAYER_UPDATE_TAG_UNLOCK(player);
831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
833 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
834 if (player->video360_metadata.is_spherical == -1) {
835 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
836 mm_player_set_attribute((MMHandleType)player, NULL,
837 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
838 if (player->video360_metadata.is_spherical == 1) {
839 LOGD("This is spherical content for 360 playback.");
840 player->is_content_spherical = TRUE;
842 LOGD("This is not spherical content");
843 player->is_content_spherical = FALSE;
846 if (player->video360_metadata.projection_type_string) {
847 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
848 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
850 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
851 player->is_content_spherical = player->is_video360_enabled = FALSE;
855 if (player->video360_metadata.stereo_mode_string) {
856 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
857 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
858 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
859 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
860 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
861 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
863 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
864 player->is_content_spherical = player->is_video360_enabled = FALSE;
870 gst_tag_list_unref(tag_list);
876 static mmplayer_track_type_e
877 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
880 case GST_STREAM_TYPE_AUDIO:
881 return MM_PLAYER_TRACK_TYPE_AUDIO;
882 case GST_STREAM_TYPE_VIDEO:
883 return MM_PLAYER_TRACK_TYPE_VIDEO;
884 case GST_STREAM_TYPE_TEXT:
885 return MM_PLAYER_TRACK_TYPE_TEXT;
887 LOGD("not supported stream stype");
888 return MM_PLAYER_TRACK_TYPE_MAX;
892 /* if retval is FALSE, it will be dropped for performance. */
894 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
896 gboolean retval = FALSE;
898 if (!(player->pipeline && player->pipeline->mainbin)) {
899 LOGE("player pipeline handle is null");
903 switch (GST_MESSAGE_TYPE(message)) {
904 case GST_MESSAGE_TAG:
905 case GST_MESSAGE_EOS:
906 case GST_MESSAGE_ERROR:
907 case GST_MESSAGE_WARNING:
908 case GST_MESSAGE_CLOCK_LOST:
909 case GST_MESSAGE_NEW_CLOCK:
910 case GST_MESSAGE_ELEMENT:
911 case GST_MESSAGE_DURATION_CHANGED:
912 case GST_MESSAGE_ASYNC_START:
913 case GST_MESSAGE_STREAM_COLLECTION:
916 case GST_MESSAGE_ASYNC_DONE:
917 case GST_MESSAGE_STATE_CHANGED:
918 /* we only handle messages from pipeline */
919 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
924 case GST_MESSAGE_BUFFERING:
926 gint buffer_percent = 0;
929 gst_message_parse_buffering(message, &buffer_percent);
930 if (buffer_percent != MAX_BUFFER_PERCENT) {
931 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
935 if (!MMPLAYER_CMD_TRYLOCK(player)) {
936 LOGW("can't get cmd lock, send msg to bus");
940 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
941 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
942 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
945 MMPLAYER_CMD_UNLOCK(player);
949 case GST_MESSAGE_STREAMS_SELECTED:
951 if (MMPLAYER_USE_DECODEBIN(player))
952 break; /* drop msg */
953 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
954 LOGD("pipeline is still under construction for adaptive streaming");
959 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
960 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
961 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
963 gint64 dur_bytes = 0L;
965 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
966 LOGE("fail to get duration.");
968 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
969 * use file information was already set on Q2 when it was created. */
970 _mm_player_streaming_set_queue2(player->streamer,
971 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
972 TRUE, /* use_buffering */
973 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
974 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
977 LOGD("GST_MESSAGE_STREAMS_SELECTED");
978 player->no_more_pad = TRUE;
979 _mmplayer_set_reconfigure_state(player, FALSE);
980 _mmplayer_pipeline_complete(NULL, player);
993 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
995 guint64 data_size = 0;
998 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1000 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1002 if (MMPLAYER_IS_HTTP_STREAMING(player))
1003 data_size = player->http_content_size;
1005 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1006 if (!player->streamer->is_adaptive_streaming) {
1007 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1011 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1012 if (!player->streamer->buffering_req.is_pre_buffering) {
1013 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1014 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1015 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1021 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1023 int ret = MM_ERROR_NONE;
1024 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1025 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1026 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1027 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1029 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1030 LOGW("do nothing for buffering msg");
1031 ret = MM_ERROR_PLAYER_INVALID_STATE;
1035 prev_state = MMPLAYER_PREV_STATE(player);
1036 current_state = MMPLAYER_CURRENT_STATE(player);
1037 target_state = MMPLAYER_TARGET_STATE(player);
1038 pending_state = MMPLAYER_PENDING_STATE(player);
1040 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1041 MMPLAYER_STATE_GET_NAME(prev_state),
1042 MMPLAYER_STATE_GET_NAME(current_state),
1043 MMPLAYER_STATE_GET_NAME(pending_state),
1044 MMPLAYER_STATE_GET_NAME(target_state),
1045 player->streamer->buffering_state);
1047 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1048 /* NOTE : if buffering has done, player has to go to target state. */
1049 switch (target_state) {
1050 case MM_PLAYER_STATE_PAUSED:
1052 switch (pending_state) {
1053 case MM_PLAYER_STATE_PLAYING:
1054 _mmplayer_gst_pause(player, TRUE);
1057 case MM_PLAYER_STATE_PAUSED:
1058 LOGD("player is already going to paused state, there is nothing to do.");
1061 case MM_PLAYER_STATE_NONE:
1062 case MM_PLAYER_STATE_NULL:
1063 case MM_PLAYER_STATE_READY:
1065 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1071 case MM_PLAYER_STATE_PLAYING:
1073 switch (pending_state) {
1074 case MM_PLAYER_STATE_NONE:
1076 if (current_state != MM_PLAYER_STATE_PLAYING)
1077 _mmplayer_gst_resume(player, TRUE);
1081 case MM_PLAYER_STATE_PAUSED:
1082 /* NOTE: It should be worked as asynchronously.
1083 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1085 if (current_state == MM_PLAYER_STATE_PLAYING) {
1086 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1087 * The current state should be changed to paused purposely to prevent state conflict.
1089 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1091 _mmplayer_gst_resume(player, TRUE);
1094 case MM_PLAYER_STATE_PLAYING:
1095 LOGD("player is already going to playing state, there is nothing to do.");
1098 case MM_PLAYER_STATE_NULL:
1099 case MM_PLAYER_STATE_READY:
1101 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1107 case MM_PLAYER_STATE_NULL:
1108 case MM_PLAYER_STATE_READY:
1109 case MM_PLAYER_STATE_NONE:
1111 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1115 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1116 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1118 switch (pending_state) {
1119 case MM_PLAYER_STATE_NONE:
1121 if (current_state != MM_PLAYER_STATE_PAUSED) {
1122 /* rtsp streaming pause makes rtsp server stop sending data. */
1123 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1124 LOGD("set pause state during buffering");
1125 _mmplayer_gst_pause(player, TRUE);
1131 case MM_PLAYER_STATE_PLAYING:
1132 /* rtsp streaming pause makes rtsp server stop sending data. */
1133 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1134 _mmplayer_gst_pause(player, TRUE);
1137 case MM_PLAYER_STATE_PAUSED:
1140 case MM_PLAYER_STATE_NULL:
1141 case MM_PLAYER_STATE_READY:
1143 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1152 static stream_variant_t *
1153 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1155 stream_variant_t *var_info = NULL;
1156 g_return_val_if_fail(self != NULL, NULL);
1158 var_info = g_new0(stream_variant_t, 1);
1159 if (!var_info) return NULL;
1160 var_info->bandwidth = self->bandwidth;
1161 var_info->width = self->width;
1162 var_info->height = self->height;
1167 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1173 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1174 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1176 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1177 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1178 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1180 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1181 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1182 player->http_content_size = (bytes > 0) ? bytes : 0;
1185 /* handling audio clip which has vbr. means duration is keep changing */
1186 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1195 __mmplayer_eos_timer_cb(gpointer u_data)
1197 mmplayer_t *player = NULL;
1198 MMHandleType attrs = 0;
1201 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1203 player = (mmplayer_t *)u_data;
1204 attrs = MMPLAYER_GET_ATTRS(player);
1206 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1210 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1211 if (ret_value != MM_ERROR_NONE)
1212 LOGE("seeking to 0 failed in repeat play");
1215 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1218 /* we are returning FALSE as we need only one posting */
1223 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1225 MMPLAYER_RETURN_IF_FAIL(player);
1227 /* post now if delay is zero */
1228 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1229 LOGD("eos delay is zero. posting EOS now");
1230 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1232 if (player->audio_decoded_cb)
1233 _mmplayer_cancel_eos_timer(player);
1238 /* cancel if existing */
1239 _mmplayer_cancel_eos_timer(player);
1241 /* init new timeout */
1242 /* NOTE : consider give high priority to this timer */
1243 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1245 player->eos_timer = g_timeout_add(delay_in_ms,
1246 __mmplayer_eos_timer_cb, player);
1248 player->context.global_default = g_main_context_default();
1249 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1251 /* check timer is valid. if not, send EOS now */
1252 if (player->eos_timer == 0) {
1253 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1254 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1259 __mmplayer_gst_pending_seek(mmplayer_t *player)
1261 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1262 int ret = MM_ERROR_NONE;
1266 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1268 if (!player->pending_seek.is_pending) {
1269 LOGD("pending seek is not reserved. nothing to do.");
1273 /* check player state if player could pending seek or not. */
1274 current_state = MMPLAYER_CURRENT_STATE(player);
1276 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1277 LOGW("try to pending seek in %s state, try next time. ",
1278 MMPLAYER_STATE_GET_NAME(current_state));
1282 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1284 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1285 if (ret != MM_ERROR_NONE)
1286 LOGE("failed to seek pending position. just keep staying current position.");
1288 player->pending_seek.is_pending = false;
1296 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1298 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1300 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1302 audiobin = player->pipeline->audiobin; /* can be null */
1303 videobin = player->pipeline->videobin; /* can be null */
1304 textbin = player->pipeline->textbin; /* can be null */
1306 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1308 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1309 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1311 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1312 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1314 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1315 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1321 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1323 mmplayer_gst_element_t *textbin;
1326 MMPLAYER_RETURN_IF_FAIL(player &&
1328 player->pipeline->textbin);
1330 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1332 textbin = player->pipeline->textbin;
1335 LOGD("Drop subtitle text after getting EOS");
1337 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1338 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1340 player->is_subtitle_force_drop = TRUE;
1342 if (player->is_subtitle_force_drop == TRUE) {
1343 LOGD("Enable subtitle data path without drop");
1345 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1346 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1348 LOGD("non-connected with external display");
1350 player->is_subtitle_force_drop = FALSE;
1356 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1358 MMHandleType attrs = 0;
1363 /* NOTE : EOS event is coming multiple time. watch out it */
1364 /* check state. we only process EOS when pipeline state goes to PLAYING */
1365 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1366 LOGD("EOS received on non-playing state. ignoring it");
1370 if (player->pipeline && player->pipeline->textbin)
1371 __mmplayer_drop_subtitle(player, TRUE);
1373 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1374 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1376 /* rewind if repeat count is greater then zero */
1377 /* get play count */
1378 attrs = MMPLAYER_GET_ATTRS(player);
1380 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1382 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1384 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1385 if (player->playback_rate < 0.0) {
1386 player->resumed_by_rewind = TRUE;
1387 _mmplayer_set_mute((MMHandleType)player, false);
1388 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1391 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1394 player->sent_bos = FALSE;
1396 LOGD("do not post eos msg for repeating");
1401 if (player->pipeline)
1402 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1404 /* post eos message to application */
1405 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1407 /* reset last position */
1408 player->last_position = 0;
1415 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1417 GError *error = NULL;
1418 gchar *debug = NULL;
1422 /* generating debug info before returning error */
1423 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1425 /* get error code */
1426 gst_message_parse_error(msg, &error, &debug);
1428 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1429 /* Note : the streaming error from the streaming source is handled
1430 * using __mmplayer_handle_streaming_error.
1432 __mmplayer_handle_streaming_error(player, msg, error);
1434 /* dump state of all element */
1435 _mmplayer_dump_pipeline_state(player);
1437 /* translate gst error code to msl error code. then post it
1438 * to application if needed
1440 __mmplayer_handle_gst_error(player, msg, error);
1443 LOGE("error debug : %s", debug);
1446 MMPLAYER_FREEIF(debug);
1447 g_error_free(error);
1454 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1456 MMMessageParamType msg_param = {0, };
1457 int bRet = MM_ERROR_NONE;
1460 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1462 if (!MMPLAYER_IS_STREAMING(player)) {
1463 LOGW("this is not streaming playback.");
1467 MMPLAYER_CMD_LOCK(player);
1469 if (!player->streamer) {
1470 LOGW("Pipeline is shutting down");
1471 MMPLAYER_CMD_UNLOCK(player);
1475 /* ignore the remained buffering message till getting 100% msg */
1476 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1477 gint buffer_percent = 0;
1479 gst_message_parse_buffering(msg, &buffer_percent);
1481 if (buffer_percent == MAX_BUFFER_PERCENT) {
1482 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1483 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1484 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1486 MMPLAYER_CMD_UNLOCK(player);
1490 /* ignore the remained buffering message */
1491 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1492 gint buffer_percent = 0;
1494 gst_message_parse_buffering(msg, &buffer_percent);
1496 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1497 player->streamer->buffering_percent, buffer_percent);
1499 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1500 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1501 player->streamer->buffering_req.is_pre_buffering = FALSE;
1503 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1505 LOGD("interrupted buffering - ignored the remained buffering msg!");
1506 MMPLAYER_CMD_UNLOCK(player);
1511 __mmplayer_update_buffer_setting(player, msg);
1513 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1515 if (bRet == MM_ERROR_NONE) {
1516 msg_param.connection.buffering = player->streamer->buffering_percent;
1517 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1519 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1520 player->pending_resume &&
1521 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1523 player->is_external_subtitle_added_now = FALSE;
1524 player->pending_resume = FALSE;
1525 _mmplayer_resume((MMHandleType)player);
1528 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1529 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1531 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1532 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1533 player->seek_state = MMPLAYER_SEEK_NONE;
1534 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1535 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1536 /* Considering the async state transition in case of RTSP.
1537 After getting state change gst msg, seek completed msg will be posted. */
1538 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1542 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1543 if (!player->streamer) {
1544 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1545 MMPLAYER_CMD_UNLOCK(player);
1549 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1551 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1552 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1554 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1555 msg_param.connection.buffering = player->streamer->buffering_percent;
1556 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1558 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1561 msg_param.connection.buffering = player->streamer->buffering_percent;
1562 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1565 MMPLAYER_CMD_UNLOCK(player);
1573 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1575 mmplayer_gst_element_t *mainbin;
1576 GstState oldstate = GST_STATE_NULL;
1577 GstState newstate = GST_STATE_NULL;
1578 GstState pending = GST_STATE_NULL;
1581 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1583 mainbin = player->pipeline->mainbin;
1585 /* we only handle messages from pipeline */
1586 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1589 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pending);
1591 LOGD("state changed [%s] : %s ---> %s final : %s",
1592 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1593 gst_element_state_get_name((GstState)oldstate),
1594 gst_element_state_get_name((GstState)newstate),
1595 gst_element_state_get_name((GstState)pending));
1597 if (newstate == GST_STATE_PLAYING) {
1598 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1600 int retVal = MM_ERROR_NONE;
1601 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1603 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1605 if (MM_ERROR_NONE != retVal)
1606 LOGE("failed to seek pending position. just keep staying current position.");
1608 player->pending_seek.is_pending = false;
1612 if (oldstate == newstate) {
1613 LOGD("pipeline reports state transition to old state");
1618 case GST_STATE_PAUSED:
1620 gboolean prepare_async = FALSE;
1622 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1623 // managed prepare async case
1624 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1625 LOGD("checking prepare mode for async transition - %d", prepare_async);
1628 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1629 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1631 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1632 _mm_player_streaming_set_content_bitrate(player->streamer,
1633 player->total_maximum_bitrate, player->total_bitrate);
1635 if (player->pending_seek.is_pending) {
1636 LOGW("trying to do pending seek");
1637 MMPLAYER_CMD_LOCK(player);
1638 __mmplayer_gst_pending_seek(player);
1639 MMPLAYER_CMD_UNLOCK(player);
1645 case GST_STATE_PLAYING:
1647 if (MMPLAYER_IS_STREAMING(player)) {
1648 // managed prepare async case when buffering is completed
1649 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1650 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1651 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1652 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1654 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1656 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1657 if (player->streamer->buffering_percent < 100) {
1659 MMMessageParamType msg_param = {0, };
1660 LOGW("Posting Buffering Completed Message to Application !!!");
1662 msg_param.connection.buffering = 100;
1663 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1668 if (player->gapless.stream_changed) {
1669 _mmplayer_update_content_attrs(player, ATTR_ALL);
1670 player->gapless.stream_changed = FALSE;
1673 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1674 player->seek_state = MMPLAYER_SEEK_NONE;
1675 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1679 case GST_STATE_VOID_PENDING:
1680 case GST_STATE_NULL:
1681 case GST_STATE_READY:
1691 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1693 const gchar *structure_name;
1694 gint count = 0, idx = 0;
1697 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1699 if (gst_message_get_structure(msg) == NULL)
1702 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1703 if (!structure_name)
1706 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1708 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1709 const GValue *var_info = NULL;
1711 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1712 if (var_info != NULL) {
1713 if (player->adaptive_info.var_list)
1714 g_list_free_full(player->adaptive_info.var_list, g_free);
1716 /* share addr or copy the list */
1717 player->adaptive_info.var_list =
1718 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1720 count = g_list_length(player->adaptive_info.var_list);
1722 stream_variant_t *temp = NULL;
1724 /* print out for debug */
1725 LOGD("num of variant_info %d", count);
1726 for (idx = 0; idx < count; idx++) {
1727 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1729 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1735 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1736 gint num_buffers = 0;
1737 gint extra_num_buffers = 0;
1739 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1740 LOGD("video_num_buffers : %d", num_buffers);
1741 mm_player_set_attribute((MMHandleType)player, NULL,
1742 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1745 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1746 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1747 mm_player_set_attribute((MMHandleType)player, NULL,
1748 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1753 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1754 _mmplayer_track_update_text_attr_info(player, msg);
1756 /* custom message */
1757 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1758 MMMessageParamType msg_param = {0,};
1759 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1760 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1763 /* custom message for RTSP attribute :
1764 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1765 sdp which has contents info is received when rtsp connection is opened.
1766 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1767 if (!strcmp(structure_name, "rtspsrc_properties")) {
1768 g_autofree gchar *audio_codec = NULL;
1769 g_autofree gchar *video_codec = NULL;
1770 g_autofree gchar *video_frame_size = NULL;
1772 gst_structure_get(gst_message_get_structure(msg),
1773 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1774 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1775 player->streaming_type = _mmplayer_get_stream_service_type(player);
1777 gst_structure_get(gst_message_get_structure(msg),
1778 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1779 LOGD("rtsp_audio_codec : %s", audio_codec);
1781 mm_player_set_attribute((MMHandleType)player, NULL,
1782 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1784 gst_structure_get(gst_message_get_structure(msg),
1785 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1786 LOGD("rtsp_video_codec : %s", video_codec);
1788 mm_player_set_attribute((MMHandleType)player, NULL,
1789 "content_video_codec", video_codec, strlen(video_codec), NULL);
1791 gst_structure_get(gst_message_get_structure(msg),
1792 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1793 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1794 if (video_frame_size) {
1795 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1796 mm_player_set_attribute((MMHandleType)player, NULL,
1797 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1798 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1800 g_strfreev(res_str);
1809 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1811 mmplayer_gst_element_t *mainbin;
1814 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1816 mainbin = player->pipeline->mainbin;
1818 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1820 /* we only handle messages from pipeline */
1821 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1824 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1825 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1826 player->seek_state = MMPLAYER_SEEK_NONE;
1827 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1828 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1829 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1830 LOGD("sync %s state(%s) with parent state(%s)",
1831 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1832 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1833 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1835 /* In case of streaming, pause is required before finishing seeking by buffering.
1836 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1837 Because the buffering state is controlled according to the state transition for force resume,
1838 the decodebin state should be paused as player state. */
1839 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1842 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1843 (player->streamer) &&
1844 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1845 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1846 GstQuery *query = NULL;
1847 gboolean busy = FALSE;
1850 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1851 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1852 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1853 gst_query_parse_buffering_percent(query, &busy, &percent);
1854 gst_query_unref(query);
1856 LOGD("buffered percent(%s): %d",
1857 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1861 __mmplayer_handle_buffering_playback(player);
1864 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1874 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1876 GValue val = { 0, };
1878 guint indent = GPOINTER_TO_UINT(user_data);
1880 if (!gst_tag_list_copy_value(&val, tags, tag))
1883 if (G_VALUE_HOLDS_STRING(&val))
1884 str = g_value_dup_string(&val);
1886 str = gst_value_serialize(&val);
1888 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1890 g_value_unset(&val);
1895 __mmplayer_dump_collection(GstStreamCollection * collection)
1899 GstTagList *tags = NULL;
1901 GstCaps *caps = NULL;
1903 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1904 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1905 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1906 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1907 gst_stream_get_stream_flags(stream));
1908 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1910 caps = gst_stream_get_caps(stream);
1912 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1913 gst_caps_unref(caps);
1917 tags = gst_stream_get_tags(stream);
1920 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1921 gst_tag_list_unref(tags);
1928 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1929 GstStream *stream, GParamSpec *pspec, gpointer data)
1931 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1932 gst_stream_get_stream_id(stream), pspec->name, collection);
1933 if (g_str_equal(pspec->name, "caps")) {
1934 GstCaps *caps = gst_stream_get_caps(stream);
1935 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1936 gst_caps_unref(caps);
1940 if (g_str_equal (pspec->name, "tags")) {
1941 GstTagList *tags = gst_stream_get_tags(stream);
1944 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1945 gst_tag_list_unref(tags);
1952 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1954 mmplayer_t *player = (mmplayer_t *)(data);
1956 MMPLAYER_RETURN_IF_FAIL(player);
1957 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1959 switch (GST_MESSAGE_TYPE(msg)) {
1960 case GST_MESSAGE_UNKNOWN:
1961 LOGD("unknown message received");
1964 case GST_MESSAGE_EOS:
1965 LOGD("GST_MESSAGE_EOS received");
1966 __mmplayer_gst_handle_eos_message(player, msg);
1969 case GST_MESSAGE_ERROR:
1970 _mmplayer_set_reconfigure_state(player, FALSE);
1971 __mmplayer_gst_handle_error_message(player, msg);
1974 case GST_MESSAGE_WARNING:
1977 GError *error = NULL;
1979 gst_message_parse_warning(msg, &error, &debug);
1981 LOGD("warning : %s", error->message);
1982 LOGD("debug : %s", debug);
1984 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1986 MMPLAYER_FREEIF(debug);
1987 g_error_free(error);
1991 case GST_MESSAGE_TAG:
1993 LOGD("GST_MESSAGE_TAG");
1994 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1995 LOGW("failed to extract tags from gstmessage");
1999 case GST_MESSAGE_BUFFERING:
2000 __mmplayer_gst_handle_buffering_message(player, msg);
2003 case GST_MESSAGE_STATE_CHANGED:
2004 __mmplayer_gst_handle_state_message(player, msg);
2007 case GST_MESSAGE_CLOCK_LOST:
2009 GstClock *clock = NULL;
2010 gboolean need_new_clock = FALSE;
2012 gst_message_parse_clock_lost(msg, &clock);
2013 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2015 if (!player->videodec_linked)
2016 need_new_clock = TRUE;
2017 else if (!player->ini.use_system_clock)
2018 need_new_clock = TRUE;
2020 if (need_new_clock) {
2021 LOGD("Provide clock is TRUE, do pause->resume");
2022 _mmplayer_gst_pause(player, FALSE);
2023 _mmplayer_gst_resume(player, FALSE);
2028 case GST_MESSAGE_NEW_CLOCK:
2030 GstClock *clock = NULL;
2031 gst_message_parse_new_clock(msg, &clock);
2032 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2036 case GST_MESSAGE_ELEMENT:
2037 __mmplayer_gst_handle_element_message(player, msg);
2040 case GST_MESSAGE_DURATION_CHANGED:
2042 LOGD("GST_MESSAGE_DURATION_CHANGED");
2043 if (!__mmplayer_gst_handle_duration(player, msg))
2044 LOGW("failed to update duration");
2048 case GST_MESSAGE_ASYNC_START:
2049 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2052 case GST_MESSAGE_ASYNC_DONE:
2053 __mmplayer_gst_handle_async_done_message(player, msg);
2055 case GST_MESSAGE_STREAM_COLLECTION:
2057 GstStreamCollection *collection = NULL;
2058 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2060 gst_message_parse_stream_collection(msg, &collection);
2062 __mmplayer_dump_collection(collection);
2063 if (player->collection && player->stream_notify_id) {
2064 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2065 player->stream_notify_id = 0;
2067 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2068 if (player->collection) {
2069 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2070 (GCallback)__mmplayer_stream_notify_cb, player);
2072 gst_object_unref(collection);
2075 case GST_MESSAGE_STREAMS_SELECTED:
2077 GstStreamCollection *collection = NULL;
2078 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2080 gst_message_parse_streams_selected(msg, &collection);
2082 guint len = gst_message_streams_selected_get_size(msg);
2083 for (guint i = 0; i < len; i++) {
2084 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2085 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2086 gst_stream_get_stream_type(stream));
2087 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2088 LOGD("not supported track type");
2089 gst_object_unref(stream);
2092 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2093 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2094 int stream_index = INVALID_TRACK_INDEX;
2095 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2096 player->track[type].active_track_index = stream_index;
2097 LOGD("selected this stream, update active idx : %d",
2098 player->track[type].active_track_index);
2101 gst_object_unref(stream);
2103 gst_object_unref(collection);
2108 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2109 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2110 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2111 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2112 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2113 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2114 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2115 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2116 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2117 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2118 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2119 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2120 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2121 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2122 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2129 /* should not call 'gst_message_unref(msg)' */
2133 static GstBusSyncReply
2134 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2136 mmplayer_t *player = (mmplayer_t *)data;
2137 GstBusSyncReply reply = GST_BUS_DROP;
2139 if (!(player->pipeline && player->pipeline->mainbin)) {
2140 LOGE("player pipeline handle is null");
2141 return GST_BUS_PASS;
2144 if (!__mmplayer_gst_check_useful_message(player, message)) {
2145 gst_message_unref(message);
2146 return GST_BUS_DROP;
2149 switch (GST_MESSAGE_TYPE(message)) {
2150 case GST_MESSAGE_TAG:
2151 __mmplayer_gst_extract_tag_from_msg(player, message);
2155 GstTagList *tags = NULL;
2157 gst_message_parse_tag(message, &tags);
2159 LOGE("TAGS received from element \"%s\".",
2160 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2162 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2163 gst_tag_list_unref(tags);
2171 case GST_MESSAGE_DURATION_CHANGED:
2172 __mmplayer_gst_handle_duration(player, message);
2174 case GST_MESSAGE_ELEMENT:
2176 const gchar *klass = NULL;
2177 klass = gst_element_factory_get_metadata
2178 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2179 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2180 reply = GST_BUS_PASS;
2183 __mmplayer_gst_handle_element_message(player, message);
2186 case GST_MESSAGE_ASYNC_DONE:
2187 /* NOTE:Don't call gst_callback directly
2188 * because previous frame can be showed even though this message is received for seek.
2191 reply = GST_BUS_PASS;
2195 if (reply == GST_BUS_DROP)
2196 gst_message_unref(message);
2202 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2204 GstElement *appsrc = element;
2205 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2206 GstBuffer *buffer = NULL;
2207 GstFlowReturn ret = GST_FLOW_OK;
2210 MMPLAYER_RETURN_IF_FAIL(element);
2211 MMPLAYER_RETURN_IF_FAIL(buf);
2213 buffer = gst_buffer_new();
2215 if (buf->offset < 0 || buf->len < 0) {
2216 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2220 if (buf->offset >= buf->len) {
2221 LOGD("call eos appsrc");
2222 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2226 if (buf->len - buf->offset < size)
2227 len = buf->len - buf->offset;
2229 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2230 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2231 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2234 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2236 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2242 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2244 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2246 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2248 buf->offset = (int)size;
2254 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2256 mmplayer_t *player = (mmplayer_t *)user_data;
2257 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2258 MMMessageParamType msg_param = {0,};
2259 guint64 current_level_bytes = 0;
2261 MMPLAYER_RETURN_IF_FAIL(player);
2263 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2264 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2265 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2266 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2268 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2272 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2274 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2276 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2277 msg_param.buffer_status.stream_type = stream_type;
2278 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2279 msg_param.buffer_status.bytes = current_level_bytes;
2281 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2285 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2287 mmplayer_t *player = (mmplayer_t *)user_data;
2288 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2289 MMMessageParamType msg_param = {0,};
2290 guint64 current_level_bytes = 0;
2292 MMPLAYER_RETURN_IF_FAIL(player);
2294 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2295 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2296 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2297 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2299 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2303 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2305 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2307 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2308 msg_param.buffer_status.stream_type = stream_type;
2309 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2310 msg_param.buffer_status.bytes = current_level_bytes;
2312 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2316 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2318 mmplayer_t *player = (mmplayer_t *)user_data;
2319 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2320 MMMessageParamType msg_param = {0,};
2322 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
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 seek-data signal from %s", GST_ELEMENT_NAME(element));
2333 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2335 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2336 msg_param.seek_data.stream_type = stream_type;
2337 msg_param.seek_data.offset = position;
2339 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2345 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2347 #define MAX_LEN_NAME 20
2349 gboolean ret = FALSE;
2350 GstPad *sinkpad = NULL;
2351 gchar *prefix = NULL;
2352 gchar dec_name[MAX_LEN_NAME] = {0, };
2353 main_element_id_e elem_id = MMPLAYER_M_NUM;
2355 mmplayer_gst_element_t *mainbin = NULL;
2356 GstElement *decodebin = NULL;
2357 GstCaps *dec_caps = NULL;
2361 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2363 player->pipeline->mainbin, FALSE);
2364 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2366 mainbin = player->pipeline->mainbin;
2368 case MM_PLAYER_STREAM_TYPE_AUDIO:
2370 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2372 case MM_PLAYER_STREAM_TYPE_VIDEO:
2374 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2377 LOGE("invalid type %d", type);
2381 if (mainbin[elem_id].gst) {
2382 LOGE("elem(%d) is already created", elem_id);
2386 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2388 /* create decodebin */
2389 decodebin = gst_element_factory_make("decodebin", dec_name);
2391 LOGE("failed to create %s", dec_name);
2395 /* raw pad handling signal */
2396 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2397 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2399 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2400 before looking for any elements that can handle that stream.*/
2401 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2402 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2404 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2405 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2406 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2408 /* This signal is emitted when a element is added to the bin.*/
2409 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2410 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2412 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2413 LOGE("failed to add new decodebin");
2417 dec_caps = gst_pad_query_caps(srcpad, NULL);
2420 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2422 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2423 gst_caps_unref(dec_caps);
2426 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2428 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2429 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2432 gst_object_unref(GST_OBJECT(sinkpad));
2434 gst_element_sync_state_with_parent(decodebin);
2436 mainbin[elem_id].id = elem_id;
2437 mainbin[elem_id].gst = decodebin;
2444 gst_object_unref(GST_OBJECT(sinkpad));
2447 gst_element_set_state(decodebin, GST_STATE_NULL);
2448 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2449 gst_object_unref(decodebin);
2457 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2459 #define MAX_LEN_NAME 20
2460 mmplayer_gst_element_t *mainbin = NULL;
2461 gchar *prefix = NULL;
2462 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2464 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2465 GstElement *src = NULL, *queue = NULL;
2466 GstPad *srcpad = NULL;
2469 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2470 player->pipeline->mainbin, FALSE);
2472 mainbin = player->pipeline->mainbin;
2474 LOGD("type(%d) path is creating", type);
2476 case MM_PLAYER_STREAM_TYPE_AUDIO:
2478 if (mainbin[MMPLAYER_M_SRC].gst)
2479 src_id = MMPLAYER_M_2ND_SRC;
2481 src_id = MMPLAYER_M_SRC;
2482 queue_id = MMPLAYER_M_A_BUFFER;
2484 case MM_PLAYER_STREAM_TYPE_VIDEO:
2486 src_id = MMPLAYER_M_SRC;
2487 queue_id = MMPLAYER_M_V_BUFFER;
2489 case MM_PLAYER_STREAM_TYPE_TEXT:
2490 prefix = "subtitle";
2491 src_id = MMPLAYER_M_SUBSRC;
2492 queue_id = MMPLAYER_M_S_BUFFER;
2495 LOGE("invalid type %d", type);
2499 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2500 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2503 src = gst_element_factory_make("appsrc", src_name);
2505 LOGF("failed to create %s", src_name);
2509 mainbin[src_id].id = src_id;
2510 mainbin[src_id].gst = src;
2512 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2513 "caps", caps, NULL);
2515 /* size of many video frames are larger than default blocksize as 4096 */
2516 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2517 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2519 if (player->media_stream_buffer_max_size[type] > 0)
2520 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2522 if (player->media_stream_buffer_min_percent[type] > 0)
2523 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2525 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2526 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2528 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2529 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2530 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2531 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2532 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2533 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2536 queue = gst_element_factory_make("queue2", queue_name);
2538 LOGE("failed to create %s", queue_name);
2541 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2543 mainbin[queue_id].id = queue_id;
2544 mainbin[queue_id].gst = queue;
2546 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2547 LOGE("failed to add src");
2551 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2552 LOGE("failed to add queue");
2556 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2557 LOGE("failed to link src and queue");
2561 /* create decoder */
2562 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2564 LOGE("failed to get srcpad of queue");
2568 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2569 _mmplayer_gst_create_decoder(player, srcpad, caps);
2571 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2572 LOGE("failed to create decoder");
2573 gst_object_unref(GST_OBJECT(srcpad));
2577 gst_object_unref(GST_OBJECT(srcpad));
2581 if (mainbin[src_id].gst) {
2582 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2583 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2584 gst_object_unref(mainbin[src_id].gst);
2585 mainbin[src_id].gst = NULL;
2588 if (mainbin[queue_id].gst) {
2589 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2590 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2591 gst_object_unref(mainbin[queue_id].gst);
2592 mainbin[queue_id].gst = NULL;
2599 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2601 GstPad *sinkpad = NULL;
2602 GstCaps *caps = NULL;
2603 GstElement *new_element = NULL;
2604 GstStructure *str = NULL;
2605 const gchar *name = NULL;
2607 mmplayer_t *player = (mmplayer_t *)data;
2611 MMPLAYER_RETURN_IF_FAIL(element && pad);
2612 MMPLAYER_RETURN_IF_FAIL(player &&
2614 player->pipeline->mainbin);
2616 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2617 * num_dynamic_pad will decreased after creating a sinkbin.
2619 player->num_dynamic_pad++;
2620 LOGD("stream count inc : %d", player->num_dynamic_pad);
2622 caps = gst_pad_query_caps(pad, NULL);
2623 MMPLAYER_CHECK_NULL(caps);
2625 str = gst_caps_get_structure(caps, 0);
2626 name = gst_structure_get_string(str, "media");
2628 LOGE("cannot get mimetype from structure.");
2632 if (strstr(name, "video")) {
2634 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2636 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2637 if (player->v_stream_caps) {
2638 gst_caps_unref(player->v_stream_caps);
2639 player->v_stream_caps = NULL;
2642 new_element = gst_element_factory_make("fakesink", NULL);
2643 player->num_dynamic_pad--;
2648 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2649 LOGE("failed to autoplug for caps");
2653 gst_caps_unref(caps);
2658 /* execute new_element if created*/
2660 LOGD("adding new element to pipeline");
2662 /* set state to READY before add to bin */
2663 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2665 /* add new element to the pipeline */
2666 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2667 LOGE("failed to add autoplug element to bin");
2671 /* get pad from element */
2672 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2674 LOGE("failed to get sinkpad from autoplug element");
2679 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2680 LOGE("failed to link autoplug element");
2684 gst_object_unref(sinkpad);
2687 /* run. setting PLAYING here since streaming source is live source */
2688 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2692 gst_caps_unref(caps);
2698 STATE_CHANGE_FAILED:
2700 /* FIXIT : take care if new_element has already added to pipeline */
2702 gst_object_unref(GST_OBJECT(new_element));
2705 gst_object_unref(GST_OBJECT(sinkpad));
2708 gst_caps_unref(caps);
2710 /* FIXIT : how to inform this error to MSL ????? */
2711 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2712 * then post an error to application
2717 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2719 mmplayer_t *player = (mmplayer_t *)data;
2723 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2724 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2725 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2726 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2728 * [1] audio and video will be dumped with filesink.
2729 * [2] autoplugging is done by just using pad caps.
2730 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2731 * and the video will be dumped via filesink.
2733 if (player->num_dynamic_pad == 0) {
2734 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2736 if (!_mmplayer_gst_remove_fakesink(player,
2737 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2738 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2739 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2740 * source element are not same. To overcome this situation, this function will called
2741 * several places and several times. Therefore, this is not an error case.
2746 /* create dot before error-return. for debugging */
2747 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2749 player->no_more_pad = TRUE;
2755 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2757 GstElement *element = NULL;
2758 gchar *user_agent = NULL;
2759 MMHandleType attrs = 0;
2762 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2764 /* get profile attribute */
2765 attrs = MMPLAYER_GET_ATTRS(player);
2767 LOGE("failed to get content attribute");
2771 element = gst_element_factory_make("rtspsrc", "rtsp source");
2773 LOGE("failed to create rtspsrc element");
2778 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2780 SECURE_LOGD("user_agent : %s", user_agent);
2782 /* setting property to streaming source */
2783 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2785 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2787 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2788 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2789 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2790 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2796 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2798 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2800 mmplayer_t *player = (mmplayer_t *)data;
2801 MMHandleType attrs = 0;
2802 gchar *user_agent, *cookies, **cookie_list;
2803 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2804 user_agent = cookies = NULL;
2808 MMPLAYER_RETURN_IF_FAIL(player);
2810 LOGD("source element %s", GST_ELEMENT_NAME(source));
2812 attrs = MMPLAYER_GET_ATTRS(player);
2814 LOGE("failed to get content attribute");
2818 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2819 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2821 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2822 http_timeout = player->ini.http_timeout;
2824 SECURE_LOGD("cookies : %s", cookies);
2825 SECURE_LOGD("user_agent : %s", user_agent);
2826 LOGD("timeout : %d", http_timeout);
2828 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2830 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2831 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2832 g_strfreev(cookie_list);
2836 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2842 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2844 mmplayer_t *player = (mmplayer_t *)data;
2845 gchar *user_agent = NULL;
2846 MMHandleType attrs = 0;
2849 MMPLAYER_RETURN_IF_FAIL(player);
2851 attrs = MMPLAYER_GET_ATTRS(player);
2853 LOGE("failed to get content attribute");
2857 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2859 SECURE_LOGD("user_agent : %s", user_agent);
2862 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2868 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2870 mmplayer_t *player = (mmplayer_t *)data;
2871 GstElement *source = NULL;
2874 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2876 g_object_get(orig, pspec->name, &source, NULL);
2878 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2879 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2881 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2882 __mmplayer_http_src_setup(source, data);
2883 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2884 __mmplayer_rtsp_src_setup(source, data);
2885 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2886 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2887 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2888 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2889 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2891 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2892 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2893 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2894 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2896 gst_object_unref (source);
2902 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2903 GstStream * stream, gpointer data)
2905 #define RET_SELECT 1
2907 #define RET_DEPENDS_ON_DECODEBIN -1
2909 GstStreamType stype = gst_stream_get_stream_type(stream);
2910 mmplayer_t *player = (mmplayer_t *)data;
2911 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2912 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2913 g_autofree gchar *caps_str = NULL;
2914 GstStructure *caps_structure = NULL;
2915 int stream_index = INVALID_TRACK_INDEX;
2916 int ret = MM_ERROR_NONE;
2918 LOGD("Stream type %s flags 0x%x",
2919 gst_stream_type_get_name(stype),
2920 gst_stream_get_stream_flags(stream));
2921 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2923 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
2926 caps_str = gst_caps_to_string(caps);
2927 caps_structure = gst_caps_get_structure(caps, 0);
2928 const gchar *mime = gst_structure_get_name(caps_structure);
2930 LOGD(" caps: %s", caps_str);
2932 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2933 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2934 LOGW("skip [%s] by unsupported codec keyword [%s]",
2935 mime, player->ini.unsupported_codec_keyword[idx]);
2937 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2941 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2942 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2943 LOGD("No caps info, depends on decodebin");
2944 _mmplayer_track_update_stream(player, type, stream);
2945 return RET_DEPENDS_ON_DECODEBIN;
2948 LOGD("No caps info, skip it");
2953 case GST_STREAM_TYPE_AUDIO:
2955 if (caps_structure) {
2956 gint samplerate = 0;
2959 gst_structure_get_int(caps_structure, "rate", &samplerate);
2960 gst_structure_get_int(caps_structure, "channels", &channels);
2961 if (samplerate == 0 && channels > 0) {
2962 LOGW("Skip corrupted audio stream");
2966 if (g_strrstr(caps_str, "mobile-xmf"))
2967 mm_player_set_attribute((MMHandleType)player, NULL,
2968 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2972 case GST_STREAM_TYPE_VIDEO:
2974 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2975 LOGD("do not support muti track video");
2979 // FIXME: it cause block during preparing
2980 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2983 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2984 /* don't make video because of not required */
2985 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2986 (!player->set_mode.video_export)) {
2987 LOGD("no need video decoding, skip video stream");
2992 if (caps_structure) {
2995 gst_structure_get_int(caps_structure, "width", &width);
2997 if (player->v_stream_caps) {
2998 gst_caps_unref(player->v_stream_caps);
2999 player->v_stream_caps = NULL;
3002 player->v_stream_caps = gst_caps_copy(caps);
3003 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3008 case GST_STREAM_TYPE_TEXT:
3011 LOGW("Skip not supported stream type");
3015 _mmplayer_track_update_stream(player, type, stream);
3017 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3019 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3020 (ret == MM_ERROR_NONE)) {
3021 player->track[type].active_track_index = stream_index;
3022 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3023 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3024 _mmplayer_set_audio_attrs(player, caps);
3028 if (player->track[type].active_track_index == stream_index) {
3029 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3033 LOGD("Skip stream");
3038 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3039 GstStream * stream, gpointer data)
3041 mmplayer_t *player = (mmplayer_t *)data;
3042 GstStreamType stype = gst_stream_get_stream_type(stream);
3045 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3047 LOGD("stream type %s", gst_stream_type_get_name(stype));
3049 /* public does not support audio hw decoder at the moment */
3051 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3052 LOGW("video decoder resource is already acquired, skip it.");
3056 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3057 LOGE("failed to acquire video decoder resource");
3060 player->interrupted_by_resource = FALSE;
3066 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3068 GstIterator *iter = NULL;
3069 GValue item = {0, };
3070 GstElement *ch_element = NULL;
3071 GstElementFactory *ch_factory = NULL;
3074 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3076 iter = gst_bin_iterate_recurse(bin);
3077 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3079 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3080 ch_element = g_value_get_object(&item);
3081 ch_factory = gst_element_get_factory(ch_element);
3082 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3083 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3084 LOGD("Find %s element", element_name);
3088 g_value_reset(&item);
3090 gst_iterator_free(iter);
3096 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3098 mmplayer_t *player = (mmplayer_t *)data;
3100 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3102 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3103 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3104 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3106 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3107 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3108 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3111 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3113 mmplayer_t *player = (mmplayer_t *)data;
3114 int video_codec_type = 0;
3115 int audio_codec_type = 0;
3117 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3119 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3120 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3122 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3124 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3125 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3126 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3127 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3129 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3130 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3134 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3136 gchar *factory_name = NULL;
3137 mmplayer_t *player = (mmplayer_t *)data;
3140 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3142 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3144 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3146 if (g_strrstr(factory_name, "urisourcebin")) {
3147 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3149 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3151 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3153 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3155 LOGW("failed to find decodebin3");
3157 } else if (g_strrstr(factory_name, "parsebin")) {
3158 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3159 __mmplayer_parsebin_setup(GST_BIN(element), data);
3161 _mmplayer_gst_element_added(child, element, data);
3166 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3170 MMPLAYER_RETURN_IF_FAIL(player);
3171 MMPLAYER_RETURN_IF_FAIL(removed_element);
3173 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3175 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3176 GList *node = player->signals[type];
3178 GList *next_node = node->next;
3179 mmplayer_signal_item_t *item = node->data;
3180 if (item && item->obj == G_OBJECT(removed_element)) {
3181 player->signals[type] = g_list_delete_link(player->signals[type], node);
3182 MMPLAYER_FREEIF(item);
3192 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3194 mmplayer_t *player = (mmplayer_t *)data;
3198 MMPLAYER_RETURN_IF_FAIL(player);
3200 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3202 __mmplayer_delete_signal_connection(player, element);
3208 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3210 GstElement *uridecodebin3 = NULL;
3213 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3215 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3216 if (!uridecodebin3) {
3217 LOGE("failed to create uridecodebin3");
3222 SECURE_LOGD("uri : %s", player->profile.uri);
3224 /* setting property to streaming source */
3225 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3226 "message-forward", TRUE,
3227 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3228 "use-buffering", TRUE, 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_position(mmplayer_t *player, gint64 position)
3409 gint64 dur_nsec = 0;
3410 gint64 pos_nsec = 0;
3413 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3415 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3416 return MM_ERROR_NONE;
3418 /* NOTE : duration cannot be zero except live streaming.
3419 * Since some element could have some timing problem with querying duration, try again.
3421 if (player->duration == 0) {
3422 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3423 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3424 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3425 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3426 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3427 player->pending_seek.is_pending = true;
3428 player->pending_seek.pos = position;
3429 player->seek_state = MMPLAYER_SEEK_NONE;
3430 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3431 return MM_ERROR_PLAYER_NO_OP;
3433 player->seek_state = MMPLAYER_SEEK_NONE;
3434 return MM_ERROR_PLAYER_SEEK;
3437 player->duration = dur_nsec;
3440 if (player->duration > 0 && player->duration < position) {
3441 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3442 return MM_ERROR_INVALID_ARGUMENT;
3445 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3446 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3447 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3448 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3449 player->seek_state = MMPLAYER_SEEK_NONE;
3450 return MM_ERROR_PLAYER_NO_OP;
3455 return MM_ERROR_NONE;
3459 __mmplayer_gst_check_seekable(mmplayer_t *player)
3461 GstQuery *query = NULL;
3462 gboolean seekable = FALSE;
3464 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3468 query = gst_query_new_seeking(GST_FORMAT_TIME);
3469 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3470 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3471 gst_query_unref(query);
3474 LOGW("non-seekable content");
3475 player->seek_state = MMPLAYER_SEEK_NONE;
3479 LOGW("failed to get seeking query");
3480 gst_query_unref(query); /* keep seeking operation */
3487 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3489 GstState element_state = GST_STATE_VOID_PENDING;
3490 GstState element_pending_state = GST_STATE_VOID_PENDING;
3491 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3496 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3498 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3501 ret = gst_element_set_state(element, state);
3502 if (ret == GST_STATE_CHANGE_FAILURE) {
3503 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3505 /* dump state of all element */
3506 _mmplayer_dump_pipeline_state(player);
3508 return MM_ERROR_PLAYER_INTERNAL;
3511 /* return here so state transition to be done in async mode */
3513 LOGD("async state transition. not waiting for state complete.");
3514 return MM_ERROR_NONE;
3517 /* wait for state transition */
3518 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3519 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3520 LOGE("failed to change [%s] element state to [%s] within %d sec",
3521 GST_ELEMENT_NAME(element),
3522 gst_element_state_get_name(state), timeout);
3524 LOGE(" [%s] state : %s pending : %s",
3525 GST_ELEMENT_NAME(element),
3526 gst_element_state_get_name(element_state),
3527 gst_element_state_get_name(element_pending_state));
3529 /* dump state of all element */
3530 _mmplayer_dump_pipeline_state(player);
3532 return MM_ERROR_PLAYER_INTERNAL;
3535 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3539 return MM_ERROR_NONE;
3543 _mmplayer_gst_start(mmplayer_t *player)
3545 int ret = MM_ERROR_NONE;
3546 gboolean async = FALSE;
3550 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3552 /* NOTE : if SetPosition was called before Start. do it now
3553 * streaming doesn't support it. so it should be always sync
3554 * !!create one more api to check if there is pending seek rather than checking variables
3556 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3557 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3558 ret = _mmplayer_gst_pause(player, FALSE);
3559 if (ret != MM_ERROR_NONE) {
3560 LOGE("failed to set state to PAUSED for pending seek");
3564 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3565 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3566 LOGW("failed to seek pending position. starting from the begin of content");
3569 LOGD("current state before doing transition");
3570 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3571 MMPLAYER_PRINT_STATE(player);
3573 /* set pipeline state to PLAYING */
3574 ret = _mmplayer_gst_set_state(player,
3575 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3576 if (ret != MM_ERROR_NONE) {
3577 LOGE("failed to set state to PLAYING");
3581 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3583 /* generating debug info before returning error */
3584 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3592 _mmplayer_gst_stop(mmplayer_t *player)
3594 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3595 MMHandleType attrs = 0;
3596 gboolean rewind = FALSE;
3598 int ret = MM_ERROR_NONE;
3602 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3603 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3605 LOGD("current state before doing transition");
3606 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3607 MMPLAYER_PRINT_STATE(player);
3609 attrs = MMPLAYER_GET_ATTRS(player);
3611 LOGE("cannot get content attribute");
3612 return MM_ERROR_PLAYER_INTERNAL;
3615 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3616 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3618 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3619 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3622 if (player->es_player_push_mode)
3623 /* disable the async state transition because there could be no data in the pipeline */
3624 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3627 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3629 if (player->es_player_push_mode) {
3630 /* enable the async state transition as default operation */
3631 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3634 /* return if set_state has failed */
3635 if (ret != MM_ERROR_NONE) {
3636 LOGE("failed to set state.");
3642 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3643 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3644 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3645 LOGW("failed to rewind");
3646 ret = MM_ERROR_PLAYER_SEEK;
3651 player->sent_bos = FALSE;
3653 if (player->es_player_push_mode) //for cloudgame
3656 /* wait for seek to complete */
3657 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3658 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3659 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3661 LOGE("fail to stop player.");
3662 ret = MM_ERROR_PLAYER_INTERNAL;
3663 _mmplayer_dump_pipeline_state(player);
3666 /* generate dot file if enabled */
3667 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3675 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3677 int ret = MM_ERROR_NONE;
3681 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3682 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3684 LOGD("current state before doing transition");
3685 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3686 MMPLAYER_PRINT_STATE(player);
3688 /* set pipeline status to PAUSED */
3689 ret = _mmplayer_gst_set_state(player,
3690 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3695 if (ret != MM_ERROR_NONE) {
3696 GstMessage *msg = NULL;
3697 GTimer *timer = NULL;
3698 gdouble MAX_TIMEOUT_SEC = 3;
3700 LOGE("failed to set state to PAUSED");
3702 if (!player->bus_watcher) {
3703 LOGE("there is no bus msg thread. pipeline is shutting down.");
3707 if (player->msg_posted) {
3708 LOGE("error msg is already posted.");
3712 timer = g_timer_new();
3713 g_timer_start(timer);
3715 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3718 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3720 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3721 GError *error = NULL;
3723 /* parse error code */
3724 gst_message_parse_error(msg, &error, NULL);
3726 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3727 /* Note : the streaming error from the streaming source is handled
3728 * using __mmplayer_handle_streaming_error.
3730 __mmplayer_handle_streaming_error(player, msg, error);
3733 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3735 if (error->domain == GST_STREAM_ERROR)
3736 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3737 else if (error->domain == GST_RESOURCE_ERROR)
3738 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3739 else if (error->domain == GST_LIBRARY_ERROR)
3740 ret = __mmplayer_gst_handle_library_error(player, error->code);
3741 else if (error->domain == GST_CORE_ERROR)
3742 ret = __mmplayer_gst_handle_core_error(player, error->code);
3744 g_error_free(error);
3746 player->msg_posted = TRUE;
3748 gst_message_unref(msg);
3750 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3752 gst_object_unref(bus);
3753 g_timer_stop(timer);
3754 g_timer_destroy(timer);
3759 if (MMPLAYER_USE_DECODEBIN(player)) {
3760 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3761 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3762 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3765 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3768 /* generate dot file before returning error */
3769 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3777 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3779 int ret = MM_ERROR_NONE;
3784 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3785 MM_ERROR_PLAYER_NOT_INITIALIZED);
3787 LOGD("current state before doing transition");
3788 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3789 MMPLAYER_PRINT_STATE(player);
3792 LOGD("do async state transition to PLAYING");
3794 /* set pipeline state to PLAYING */
3795 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3797 ret = _mmplayer_gst_set_state(player,
3798 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3799 if (ret != MM_ERROR_NONE) {
3800 LOGE("failed to set state to PLAYING");
3805 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3808 /* generate dot file */
3809 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3816 /* sending event to one of sinkelements */
3818 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3820 GstEvent *event2 = NULL;
3821 GList *sinks = NULL;
3822 gboolean res = FALSE;
3825 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3826 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3828 /* While adding subtitles in live feeds seek is getting called.
3829 Adding defensive check in framework layer.*/
3830 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3831 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3832 LOGE("Should not send seek event during live playback");
3837 if (player->play_subtitle)
3838 event2 = gst_event_copy((const GstEvent *)event);
3840 sinks = player->sink_elements;
3842 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3844 if (GST_IS_ELEMENT(sink)) {
3845 /* keep ref to the event */
3846 gst_event_ref(event);
3848 if ((res = gst_element_send_event(sink, event))) {
3849 LOGD("sending event[%s] to sink element [%s] success!",
3850 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3852 /* rtsp case, async_done is not called after seek during pause state */
3853 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3854 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3855 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3856 LOGD("RTSP seek completed, after pause state..");
3857 player->seek_state = MMPLAYER_SEEK_NONE;
3858 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3864 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3865 sinks = g_list_next(sinks);
3872 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3873 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3876 sinks = g_list_next(sinks);
3879 /* Note : Textbin is not linked to the video or audio bin.
3880 * It needs to send the event to the text sink separately.
3882 if (player->play_subtitle && player->pipeline) {
3883 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3885 if (GST_IS_ELEMENT(text_sink)) {
3886 /* keep ref to the event */
3887 gst_event_ref(event2);
3889 if ((res = gst_element_send_event(text_sink, event2)))
3890 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3891 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3893 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3894 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3896 gst_event_unref(event2);
3900 gst_event_unref(event);
3908 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3909 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3910 gint64 cur, GstSeekType stop_type, gint64 stop)
3912 GstEvent *event = NULL;
3913 gboolean result = FALSE;
3917 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3919 if (player->pipeline && player->pipeline->textbin)
3920 __mmplayer_drop_subtitle(player, FALSE);
3922 event = gst_event_new_seek(rate, format, flags, cur_type,
3923 cur, stop_type, stop);
3925 result = _mmplayer_gst_send_event_to_sink(player, event);
3933 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3935 int ret = MM_ERROR_NONE;
3936 gint64 pos_nsec = 0;
3937 gboolean accurate = FALSE;
3938 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3941 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3942 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3944 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3945 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3948 ret = __mmplayer_gst_check_position(player, position);
3949 if (ret != MM_ERROR_NONE) {
3950 LOGW("result of check position info 0x%X", ret);
3951 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3954 if (!__mmplayer_gst_check_seekable(player))
3955 return MM_ERROR_PLAYER_NO_OP;
3957 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3958 position, player->playback_rate, player->duration);
3960 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3961 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3962 This causes problem is position calculation during normal pause resume scenarios also.
3963 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3964 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3965 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3966 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3967 LOGW("getting current position failed in seek");
3969 player->last_position = pos_nsec;
3970 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3973 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3974 LOGD("not completed seek");
3975 return MM_ERROR_PLAYER_DOING_SEEK;
3978 if (!internal_called)
3979 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3981 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3982 that's why set position through property. */
3983 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3984 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3985 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3986 (!player->videodec_linked) && (!player->audiodec_linked)) {
3988 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3989 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3991 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3992 player->seek_state = MMPLAYER_SEEK_NONE;
3993 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3995 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3997 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3999 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4001 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4002 GST_FORMAT_TIME, seek_flags,
4003 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4004 LOGE("failed to set position");
4009 /* NOTE : store last seeking point to overcome some bad operation
4010 * (returning zero when getting current position) of some elements
4012 player->last_position = position;
4014 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4015 if (player->playback_rate > 1.0)
4016 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4018 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4019 LOGD("buffering should be reset after seeking");
4020 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4021 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4025 return MM_ERROR_NONE;
4028 player->pending_seek.is_pending = true;
4029 player->pending_seek.pos = position;
4031 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4032 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4033 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4034 player->pending_seek.pos);
4036 return MM_ERROR_NONE;
4039 player->seek_state = MMPLAYER_SEEK_NONE;
4040 return MM_ERROR_PLAYER_SEEK;
4044 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4046 #define TRICKPLAY_OFFSET GST_MSECOND
4048 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4049 gint64 pos_nsec = 0;
4050 gboolean ret = TRUE;
4052 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4053 MM_ERROR_PLAYER_NOT_INITIALIZED);
4055 current_state = MMPLAYER_CURRENT_STATE(player);
4057 /* NOTE : query position except paused state to overcome some bad operation
4058 * please refer to below comments in details
4060 if (current_state != MM_PLAYER_STATE_PAUSED)
4061 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4063 /* NOTE : get last point to overcome some bad operation of some elements
4064 *(returning zero when getting current position in paused state
4065 * and when failed to get position during seeking
4067 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4068 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4070 if (player->playback_rate < 0.0)
4071 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4073 pos_nsec = player->last_position;
4076 pos_nsec = player->last_position;
4078 player->last_position = pos_nsec;
4080 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4083 if (player->duration > 0 && pos_nsec > player->duration)
4084 pos_nsec = player->duration;
4086 player->last_position = pos_nsec;
4089 *position = pos_nsec;
4091 return MM_ERROR_NONE;
4095 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4097 #define STREAMING_IS_FINISHED 0
4098 #define BUFFERING_MAX_PER 100
4099 #define DEFAULT_PER_VALUE -1
4100 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4102 mmplayer_gst_element_t *mainbin = NULL;
4103 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4104 gint64 buffered_total = 0;
4105 gint64 position = 0;
4106 gint buffered_sec = -1;
4107 GstBufferingMode mode = GST_BUFFERING_STREAM;
4108 gint64 content_size_time = player->duration;
4109 guint64 content_size_bytes = player->http_content_size;
4111 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4113 player->pipeline->mainbin,
4114 MM_ERROR_PLAYER_NOT_INITIALIZED);
4116 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4121 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4122 /* and rtsp is not ready yet. */
4123 LOGW("it's only used for http streaming case");
4124 return MM_ERROR_PLAYER_NO_OP;
4127 if (content_size_time <= 0 || content_size_bytes <= 0) {
4128 LOGW("there is no content size");
4129 return MM_ERROR_NONE;
4132 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4133 LOGW("fail to get current position");
4134 return MM_ERROR_NONE;
4137 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4138 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4140 mainbin = player->pipeline->mainbin;
4141 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4143 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4144 GstQuery *query = NULL;
4145 gint byte_in_rate = 0, byte_out_rate = 0;
4146 gint64 estimated_total = 0;
4148 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4149 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4150 LOGW("fail to get buffering query from queue2");
4152 gst_query_unref(query);
4153 return MM_ERROR_NONE;
4156 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4157 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4159 if (mode == GST_BUFFERING_STREAM) {
4160 /* using only queue in case of push mode(ts / mp3) */
4161 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4162 GST_FORMAT_BYTES, &buffered_total)) {
4163 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4164 end_per = 100 * buffered_total / content_size_bytes;
4167 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4169 guint num_of_ranges = 0;
4170 gint64 start_byte = 0, stop_byte = 0;
4172 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4173 if (estimated_total != STREAMING_IS_FINISHED) {
4174 /* buffered size info from queue2 */
4175 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4176 for (idx = 0; idx < num_of_ranges; idx++) {
4177 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4178 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4180 buffered_total += (stop_byte - start_byte);
4183 end_per = BUFFERING_MAX_PER;
4186 gst_query_unref(query);
4189 if (end_per == DEFAULT_PER_VALUE) {
4190 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4192 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4194 /* buffered size info from multiqueue */
4195 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4196 guint curr_size_bytes = 0;
4197 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4198 "curr-size-bytes", &curr_size_bytes, NULL);
4199 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4200 buffered_total += (gint64)curr_size_bytes;
4203 if (avg_byterate > 0)
4204 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4205 else if (player->total_maximum_bitrate > 0)
4206 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4207 else if (player->total_bitrate > 0)
4208 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4210 if (buffered_sec >= 0)
4211 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4215 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4216 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4218 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4219 buffered_total, buffered_sec, *start_pos, *end_pos);
4221 return MM_ERROR_NONE;
4225 _mmplayer_gst_create_source(mmplayer_t *player)
4227 GstElement *element = NULL;
4230 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4231 player->pipeline->mainbin, NULL);
4233 /* setup source for gapless play */
4234 switch (player->profile.uri_type) {
4236 case MM_PLAYER_URI_TYPE_FILE:
4237 element = __mmplayer_gst_make_file_src(player);
4239 case MM_PLAYER_URI_TYPE_URL_HTTP:
4240 element = __mmplayer_gst_make_http_src(player);
4243 LOGE("not support uri type %d", player->profile.uri_type);
4248 LOGE("failed to create source element");
4257 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4260 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4261 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4263 SECURE_LOGD("uri : %s", player->profile.uri);
4265 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4267 if ((player->v_stream_caps) &&
4268 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4269 return MM_ERROR_PLAYER_INTERNAL;
4271 if ((player->a_stream_caps) &&
4272 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4273 return MM_ERROR_PLAYER_INTERNAL;
4275 if ((player->s_stream_caps) &&
4276 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4277 return MM_ERROR_PLAYER_INTERNAL;
4280 return MM_ERROR_NONE;
4284 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4286 mmplayer_gst_element_t *mainbin = NULL;
4287 GstElement *autoplug_elem = NULL;
4290 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4291 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4293 mainbin = player->pipeline->mainbin;
4295 LOGD("uri type %d", player->profile.uri_type);
4297 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4298 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4299 return MM_ERROR_PLAYER_INTERNAL;
4302 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4303 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4306 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4307 if (!autoplug_elem) {
4308 LOGE("failed to create uridecodebin3 element");
4312 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4313 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4314 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4316 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4317 LOGE("failed to add uridecodebin to pipeline");
4321 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4322 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4323 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4325 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4326 LOGE("failed to create fakesink");
4329 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4331 /* take ownership of fakesink. we are reusing it */
4332 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4334 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4335 LOGE("failed to add fakesink to bin");
4336 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4341 return MM_ERROR_NONE;
4345 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4346 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4348 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4349 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4351 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4352 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4354 return MM_ERROR_PLAYER_INTERNAL;
4358 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4360 mmplayer_gst_element_t *mainbin = NULL;
4361 GstElement *src_elem = NULL;
4362 GstElement *autoplug_elem = NULL;
4363 GList *element_bucket = NULL;
4364 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4367 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4368 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4370 LOGD("uri type %d", player->profile.uri_type);
4372 /* create source element */
4373 switch (player->profile.uri_type) {
4374 case MM_PLAYER_URI_TYPE_URL_RTSP:
4375 src_elem = __mmplayer_gst_make_rtsp_src(player);
4377 case MM_PLAYER_URI_TYPE_URL_HTTP:
4378 src_elem = __mmplayer_gst_make_http_src(player);
4380 case MM_PLAYER_URI_TYPE_FILE:
4381 src_elem = __mmplayer_gst_make_file_src(player);
4383 case MM_PLAYER_URI_TYPE_SS:
4385 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4386 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4388 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4392 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4393 LOGD("get timeout from ini");
4394 http_timeout = player->ini.http_timeout;
4397 /* setting property to streaming source */
4398 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4401 case MM_PLAYER_URI_TYPE_MEM:
4403 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4405 src_elem = gst_element_factory_make("appsrc", "mem-source");
4407 LOGE("failed to create appsrc element");
4411 g_object_set(src_elem, "stream-type", stream_type,
4412 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4414 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4415 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4416 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4417 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4421 LOGE("not support uri type");
4426 LOGE("failed to create source element");
4427 return MM_ERROR_PLAYER_INTERNAL;
4430 mainbin = player->pipeline->mainbin;
4432 /* take source element */
4433 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4435 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4436 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4437 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4439 /* create next element for auto-plugging */
4440 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4441 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4442 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4443 if (!autoplug_elem) {
4444 LOGE("failed to create typefind element");
4448 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4449 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4450 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4451 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4452 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4453 if (!autoplug_elem) {
4454 LOGE("failed to create decodebin");
4458 /* default size of mq in decodebin is 2M
4459 * but it can cause blocking issue during seeking depends on content. */
4460 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4463 if (autoplug_elem) {
4464 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4465 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4466 mainbin[autoplug_elem_id].gst = autoplug_elem;
4468 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4471 /* add elements to pipeline */
4472 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4473 LOGE("failed to add elements to pipeline");
4477 /* linking elements in the bucket by added order. */
4478 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4479 LOGE("failed to link some elements");
4483 /* FIXME: need to check whether this is required or not. */
4484 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4485 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4486 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4487 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4488 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4490 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4491 LOGE("failed to create fakesink");
4494 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4496 /* take ownership of fakesink. we are reusing it */
4497 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4499 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4500 LOGE("failed to add fakesink to bin");
4501 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4506 g_list_free(element_bucket);
4509 return MM_ERROR_NONE;
4512 g_list_free(element_bucket);
4514 if (mainbin[MMPLAYER_M_SRC].gst)
4515 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4517 if (mainbin[autoplug_elem_id].gst)
4518 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4520 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4521 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4523 mainbin[MMPLAYER_M_SRC].gst = NULL;
4524 mainbin[autoplug_elem_id].gst = NULL;
4525 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4527 return MM_ERROR_PLAYER_INTERNAL;
4531 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4534 mmplayer_gst_element_t *mainbin = NULL;
4537 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4538 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4540 mainbin = player->pipeline->mainbin;
4542 /* connect bus callback */
4543 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4545 LOGE("cannot get bus from pipeline");
4546 return MM_ERROR_PLAYER_INTERNAL;
4549 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4550 (GstBusFunc)__mmplayer_gst_msg_push, player,
4551 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4552 if (player->bus_watcher == 0) {
4553 LOGE("failed to add bus watch");
4554 return MM_ERROR_PLAYER_INTERNAL;
4557 g_mutex_init(&player->bus_watcher_mutex);
4558 g_cond_init(&player->bus_watcher_cond);
4560 player->context.thread_default = g_main_context_get_thread_default();
4561 if (player->context.thread_default == NULL) {
4562 player->context.thread_default = g_main_context_default();
4563 LOGD("thread-default context is the global default context");
4565 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4567 /* set sync handler to get tag synchronously */
4568 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4569 gst_object_unref(GST_OBJECT(bus));
4571 /* create gst bus_msb_cb thread */
4572 g_mutex_init(&player->bus_msg_thread_mutex);
4573 g_cond_init(&player->bus_msg_thread_cond);
4574 player->bus_msg_thread_exit = FALSE;
4575 player->bus_msg_thread =
4576 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4577 if (!player->bus_msg_thread) {
4578 LOGE("failed to create gst BUS msg thread");
4579 g_mutex_clear(&player->bus_msg_thread_mutex);
4580 g_cond_clear(&player->bus_msg_thread_cond);
4581 return MM_ERROR_PLAYER_INTERNAL;
4585 return MM_ERROR_NONE;
4589 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4591 int ret = MM_ERROR_NONE;
4592 mmplayer_gst_element_t *mainbin = NULL;
4593 MMMessageParamType msg_param = {0,};
4594 GstElement *element = NULL;
4595 MMHandleType attrs = 0;
4597 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4601 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4602 LOGE("player is not initialized");
4606 mainbin = player->pipeline->mainbin;
4607 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4609 attrs = MMPLAYER_GET_ATTRS(player);
4611 LOGE("fail to get attributes");
4615 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4617 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4618 LOGE("failed to parse profile");
4619 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4623 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4624 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4625 LOGE("dash or hls is not supportable");
4626 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4630 if (!MMPLAYER_USE_DECODEBIN(player)) {
4631 ret = _mmplayer_gst_build_pipeline_with_src(player);
4632 if (ret != MM_ERROR_NONE)
4635 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4636 LOGE("Failed to change state of uridecodebin3 element");
4642 element = _mmplayer_gst_create_source(player);
4644 LOGE("no source element was created");
4648 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4649 LOGE("failed to add source element to pipeline");
4650 gst_object_unref(GST_OBJECT(element));
4655 /* take source element */
4656 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4657 mainbin[MMPLAYER_M_SRC].gst = element;
4661 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4662 if (player->streamer == NULL) {
4663 player->streamer = _mm_player_streaming_create();
4664 _mm_player_streaming_initialize(player->streamer, TRUE);
4667 elem_idx = MMPLAYER_M_TYPEFIND;
4668 element = gst_element_factory_make("typefind", "typefinder");
4669 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4670 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4672 elem_idx = MMPLAYER_M_AUTOPLUG;
4673 element = _mmplayer_gst_make_decodebin(player);
4676 /* check autoplug element is OK */
4678 LOGE("can not create element(%d)", elem_idx);
4682 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4683 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4684 gst_object_unref(GST_OBJECT(element));
4689 mainbin[elem_idx].id = elem_idx;
4690 mainbin[elem_idx].gst = element;
4692 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4693 LOGE("Failed to link src - autoplug(or typefind)");
4697 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4698 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4699 LOGE("Failed to change state of src element");
4703 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4704 LOGE("Failed to change state of decodebin");
4709 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4710 LOGE("Failed to change state of src element");
4715 player->gapless.stream_changed = TRUE;
4716 player->gapless.running = TRUE;
4722 _mmplayer_set_reconfigure_state(player, FALSE);
4723 if (!player->msg_posted) {
4724 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4725 player->msg_posted = TRUE;