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 if (string == NULL) {\
770 LOGD("failed to get date/time from tag");\
774 mm_player_set_attribute((MMHandleType)player, NULL,\
775 playertag, string, strlen(string), NULL); \
776 SECURE_LOGD("metainfo year : %s", string);\
777 MMPLAYER_FREEIF(string);\
783 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
785 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
786 if (datetime != NULL) {\
787 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
788 mm_player_set_attribute((MMHandleType)player, NULL,\
789 playertag, string, strlen(string), NULL); \
790 SECURE_LOGD("metainfo year : %s", string);\
791 MMPLAYER_FREEIF(string);\
792 gst_date_time_unref(datetime);\
798 GstTagList *tag_list = NULL;
803 GstDateTime *datetime = NULL;
805 GstBuffer *buffer = NULL;
807 MMMessageParamType msg_param = {0, };
809 /* currently not used. but those are needed for above macro */
810 //guint64 v_uint64 = 0;
811 //gdouble v_double = 0;
813 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
815 /* get tag list from gst message */
816 gst_message_parse_tag(msg, &tag_list);
818 /* store tags to player attributes */
819 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
821 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
823 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
824 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
827 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
828 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
829 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
830 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
831 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
832 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
833 MMPLAYER_UPDATE_TAG_LOCK(player);
834 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
835 MMPLAYER_UPDATE_TAG_UNLOCK(player);
836 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
838 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
839 if (player->video360_metadata.is_spherical == -1) {
840 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
841 mm_player_set_attribute((MMHandleType)player, NULL,
842 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
843 if (player->video360_metadata.is_spherical == 1) {
844 LOGD("This is spherical content for 360 playback.");
845 player->is_content_spherical = TRUE;
847 LOGD("This is not spherical content");
848 player->is_content_spherical = FALSE;
851 if (player->video360_metadata.projection_type_string) {
852 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
853 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
855 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
856 player->is_content_spherical = player->is_video360_enabled = FALSE;
860 if (player->video360_metadata.stereo_mode_string) {
861 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
862 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
863 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
864 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
865 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
866 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
868 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
869 player->is_content_spherical = player->is_video360_enabled = FALSE;
875 gst_tag_list_unref(tag_list);
881 static mmplayer_track_type_e
882 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
885 case GST_STREAM_TYPE_AUDIO:
886 return MM_PLAYER_TRACK_TYPE_AUDIO;
887 case GST_STREAM_TYPE_VIDEO:
888 return MM_PLAYER_TRACK_TYPE_VIDEO;
889 case GST_STREAM_TYPE_TEXT:
890 return MM_PLAYER_TRACK_TYPE_TEXT;
892 LOGD("not supported stream stype");
893 return MM_PLAYER_TRACK_TYPE_MAX;
897 /* if retval is FALSE, it will be dropped for performance. */
899 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
901 gboolean retval = FALSE;
903 if (!(player->pipeline && player->pipeline->mainbin)) {
904 LOGE("player pipeline handle is null");
908 switch (GST_MESSAGE_TYPE(message)) {
909 case GST_MESSAGE_TAG:
910 case GST_MESSAGE_EOS:
911 case GST_MESSAGE_ERROR:
912 case GST_MESSAGE_WARNING:
913 case GST_MESSAGE_CLOCK_LOST:
914 case GST_MESSAGE_NEW_CLOCK:
915 case GST_MESSAGE_ELEMENT:
916 case GST_MESSAGE_DURATION_CHANGED:
917 case GST_MESSAGE_ASYNC_START:
918 case GST_MESSAGE_STREAM_COLLECTION:
921 case GST_MESSAGE_ASYNC_DONE:
922 case GST_MESSAGE_STATE_CHANGED:
923 /* we only handle messages from pipeline */
924 MMPLAYER_RECONFIGURE_LOCK(player);
925 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
929 MMPLAYER_RECONFIGURE_UNLOCK(player);
931 case GST_MESSAGE_BUFFERING:
933 gint buffer_percent = 0;
936 gst_message_parse_buffering(message, &buffer_percent);
937 if (buffer_percent != MAX_BUFFER_PERCENT) {
938 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
942 if (!MMPLAYER_CMD_TRYLOCK(player)) {
943 LOGW("can't get cmd lock, send msg to bus");
947 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
948 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
949 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
952 MMPLAYER_CMD_UNLOCK(player);
956 case GST_MESSAGE_STREAMS_SELECTED:
958 if (MMPLAYER_USE_DECODEBIN(player))
959 break; /* drop msg */
961 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
962 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
963 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
965 gint64 dur_bytes = 0L;
967 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
968 LOGE("fail to get duration.");
970 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
971 * use file information was already set on Q2 when it was created. */
972 _mm_player_streaming_set_queue2(player->streamer,
973 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
974 TRUE, /* use_buffering */
975 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
976 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
979 LOGD("GST_MESSAGE_STREAMS_SELECTED");
980 player->no_more_pad = TRUE;
981 _mmplayer_set_reconfigure_state(player, FALSE);
982 if (!MMPLAYER_IS_ADAPTIVE_STREAMING(player))
983 _mmplayer_pipeline_complete(NULL, player);
996 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
998 guint64 data_size = 0;
1001 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1003 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1005 if (MMPLAYER_IS_HTTP_STREAMING(player))
1006 data_size = player->http_content_size;
1008 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1009 if (!player->streamer->is_adaptive_streaming) {
1010 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1014 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1015 if (!player->streamer->buffering_req.is_pre_buffering) {
1016 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1017 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1018 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1024 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1026 int ret = MM_ERROR_NONE;
1027 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1028 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1029 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1030 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1032 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1033 LOGW("do nothing for buffering msg");
1034 ret = MM_ERROR_PLAYER_INVALID_STATE;
1038 prev_state = MMPLAYER_PREV_STATE(player);
1039 current_state = MMPLAYER_CURRENT_STATE(player);
1040 target_state = MMPLAYER_TARGET_STATE(player);
1041 pending_state = MMPLAYER_PENDING_STATE(player);
1043 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1044 MMPLAYER_STATE_GET_NAME(prev_state),
1045 MMPLAYER_STATE_GET_NAME(current_state),
1046 MMPLAYER_STATE_GET_NAME(pending_state),
1047 MMPLAYER_STATE_GET_NAME(target_state),
1048 player->streamer->buffering_state);
1050 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1051 /* NOTE : if buffering has done, player has to go to target state. */
1052 switch (target_state) {
1053 case MM_PLAYER_STATE_PAUSED:
1055 switch (pending_state) {
1056 case MM_PLAYER_STATE_PLAYING:
1057 _mmplayer_gst_pause(player, TRUE);
1060 case MM_PLAYER_STATE_PAUSED:
1061 LOGD("player is already going to paused state, there is nothing to do.");
1064 case MM_PLAYER_STATE_NONE:
1065 case MM_PLAYER_STATE_NULL:
1066 case MM_PLAYER_STATE_READY:
1068 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1074 case MM_PLAYER_STATE_PLAYING:
1076 switch (pending_state) {
1077 case MM_PLAYER_STATE_NONE:
1079 if (current_state != MM_PLAYER_STATE_PLAYING)
1080 _mmplayer_gst_resume(player, TRUE);
1084 case MM_PLAYER_STATE_PAUSED:
1085 /* NOTE: It should be worked as asynchronously.
1086 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1088 if (current_state == MM_PLAYER_STATE_PLAYING) {
1089 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1090 * The current state should be changed to paused purposely to prevent state conflict.
1092 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1094 _mmplayer_gst_resume(player, TRUE);
1097 case MM_PLAYER_STATE_PLAYING:
1098 LOGD("player is already going to playing state, there is nothing to do.");
1101 case MM_PLAYER_STATE_NULL:
1102 case MM_PLAYER_STATE_READY:
1104 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1110 case MM_PLAYER_STATE_NULL:
1111 case MM_PLAYER_STATE_READY:
1112 case MM_PLAYER_STATE_NONE:
1114 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1118 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1119 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1121 switch (pending_state) {
1122 case MM_PLAYER_STATE_NONE:
1124 if (current_state != MM_PLAYER_STATE_PAUSED) {
1125 /* rtsp streaming pause makes rtsp server stop sending data. */
1126 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1127 LOGD("set pause state during buffering");
1128 _mmplayer_gst_pause(player, TRUE);
1134 case MM_PLAYER_STATE_PLAYING:
1135 /* rtsp streaming pause makes rtsp server stop sending data. */
1136 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1137 _mmplayer_gst_pause(player, TRUE);
1140 case MM_PLAYER_STATE_PAUSED:
1143 case MM_PLAYER_STATE_NULL:
1144 case MM_PLAYER_STATE_READY:
1146 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1155 static stream_variant_t *
1156 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1158 stream_variant_t *var_info = NULL;
1159 g_return_val_if_fail(self != NULL, NULL);
1161 var_info = g_new0(stream_variant_t, 1);
1162 if (!var_info) return NULL;
1163 var_info->bandwidth = self->bandwidth;
1164 var_info->width = self->width;
1165 var_info->height = self->height;
1170 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1176 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1177 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1179 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1180 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1181 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1183 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1184 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1185 player->http_content_size = (bytes > 0) ? bytes : 0;
1188 /* handling audio clip which has vbr. means duration is keep changing */
1189 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1198 __mmplayer_eos_timer_cb(gpointer u_data)
1200 mmplayer_t *player = NULL;
1201 MMHandleType attrs = 0;
1204 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1206 player = (mmplayer_t *)u_data;
1207 attrs = MMPLAYER_GET_ATTRS(player);
1209 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1213 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1214 if (ret_value != MM_ERROR_NONE)
1215 LOGE("seeking to 0 failed in repeat play");
1218 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1221 /* we are returning FALSE as we need only one posting */
1226 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1228 MMPLAYER_RETURN_IF_FAIL(player);
1230 /* post now if delay is zero */
1231 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1232 LOGD("eos delay is zero. posting EOS now");
1233 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1235 if (player->audio_decoded_cb)
1236 _mmplayer_cancel_eos_timer(player);
1241 /* cancel if existing */
1242 _mmplayer_cancel_eos_timer(player);
1244 /* init new timeout */
1245 /* NOTE : consider give high priority to this timer */
1246 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1248 player->eos_timer = g_timeout_add(delay_in_ms,
1249 __mmplayer_eos_timer_cb, player);
1251 player->context.global_default = g_main_context_default();
1252 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1254 /* check timer is valid. if not, send EOS now */
1255 if (player->eos_timer == 0) {
1256 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1257 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1262 __mmplayer_gst_pending_seek(mmplayer_t *player)
1264 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1265 int ret = MM_ERROR_NONE;
1269 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1271 if (!player->pending_seek.is_pending) {
1272 LOGD("pending seek is not reserved. nothing to do.");
1276 /* check player state if player could pending seek or not. */
1277 current_state = MMPLAYER_CURRENT_STATE(player);
1279 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1280 LOGW("try to pending seek in %s state, try next time. ",
1281 MMPLAYER_STATE_GET_NAME(current_state));
1285 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1287 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1288 if (ret != MM_ERROR_NONE)
1289 LOGE("failed to seek pending position. just keep staying current position.");
1291 player->pending_seek.is_pending = false;
1299 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1301 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1303 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1305 audiobin = player->pipeline->audiobin; /* can be null */
1306 videobin = player->pipeline->videobin; /* can be null */
1307 textbin = player->pipeline->textbin; /* can be null */
1309 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1311 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1312 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1314 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1315 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1317 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1318 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1324 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1326 mmplayer_gst_element_t *textbin;
1329 MMPLAYER_RETURN_IF_FAIL(player &&
1331 player->pipeline->textbin);
1333 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1335 textbin = player->pipeline->textbin;
1338 LOGD("Drop subtitle text after getting EOS");
1340 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1341 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1343 player->is_subtitle_force_drop = TRUE;
1345 if (player->is_subtitle_force_drop == TRUE) {
1346 LOGD("Enable subtitle data path without drop");
1348 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1349 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1351 LOGD("non-connected with external display");
1353 player->is_subtitle_force_drop = FALSE;
1359 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1361 MMHandleType attrs = 0;
1366 /* NOTE : EOS event is coming multiple time. watch out it */
1367 /* check state. we only process EOS when pipeline state goes to PLAYING */
1368 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1369 LOGD("EOS received on non-playing state. ignoring it");
1373 if (player->pipeline && player->pipeline->textbin)
1374 __mmplayer_drop_subtitle(player, TRUE);
1376 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1377 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1379 /* rewind if repeat count is greater then zero */
1380 /* get play count */
1381 attrs = MMPLAYER_GET_ATTRS(player);
1383 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1385 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1387 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1388 if (player->playback_rate < 0.0) {
1389 player->resumed_by_rewind = TRUE;
1390 _mmplayer_set_mute((MMHandleType)player, false);
1391 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1394 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1397 player->sent_bos = FALSE;
1399 LOGD("do not post eos msg for repeating");
1404 if (player->pipeline)
1405 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1407 /* post eos message to application */
1408 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1410 /* reset last position */
1411 player->last_position = 0;
1418 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1420 GError *error = NULL;
1421 gchar *debug = NULL;
1425 /* generating debug info before returning error */
1426 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1428 /* get error code */
1429 gst_message_parse_error(msg, &error, &debug);
1431 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1432 /* Note : the streaming error from the streaming source is handled
1433 * using __mmplayer_handle_streaming_error.
1435 __mmplayer_handle_streaming_error(player, msg, error);
1437 /* dump state of all element */
1438 _mmplayer_dump_pipeline_state(player);
1440 /* translate gst error code to msl error code. then post it
1441 * to application if needed
1443 __mmplayer_handle_gst_error(player, msg, error);
1446 LOGE("error debug : %s", debug);
1449 MMPLAYER_FREEIF(debug);
1450 g_error_free(error);
1457 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1459 MMMessageParamType msg_param = {0, };
1460 int bRet = MM_ERROR_NONE;
1463 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1465 if (!MMPLAYER_IS_STREAMING(player)) {
1466 LOGW("this is not streaming playback.");
1470 MMPLAYER_CMD_LOCK(player);
1472 if (!player->streamer) {
1473 LOGW("Pipeline is shutting down");
1474 MMPLAYER_CMD_UNLOCK(player);
1478 /* ignore the remained buffering message till getting 100% msg */
1479 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1480 gint buffer_percent = 0;
1482 gst_message_parse_buffering(msg, &buffer_percent);
1484 if (buffer_percent == MAX_BUFFER_PERCENT) {
1485 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1486 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1487 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1489 MMPLAYER_CMD_UNLOCK(player);
1493 /* ignore the remained buffering message */
1494 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1495 gint buffer_percent = 0;
1497 gst_message_parse_buffering(msg, &buffer_percent);
1499 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1500 player->streamer->buffering_percent, buffer_percent);
1502 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1503 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1504 player->streamer->buffering_req.is_pre_buffering = FALSE;
1506 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1508 LOGD("interrupted buffering - ignored the remained buffering msg!");
1509 MMPLAYER_CMD_UNLOCK(player);
1514 __mmplayer_update_buffer_setting(player, msg);
1516 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1518 if (bRet == MM_ERROR_NONE) {
1519 msg_param.connection.buffering = player->streamer->buffering_percent;
1520 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1522 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1523 player->pending_resume &&
1524 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1526 player->is_external_subtitle_added_now = FALSE;
1527 player->pending_resume = FALSE;
1528 _mmplayer_resume((MMHandleType)player);
1531 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1532 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1534 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1535 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1536 player->seek_state = MMPLAYER_SEEK_NONE;
1537 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1538 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1539 /* Considering the async state transition in case of RTSP.
1540 After getting state change gst msg, seek completed msg will be posted. */
1541 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1545 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1546 if (!player->streamer) {
1547 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1548 MMPLAYER_CMD_UNLOCK(player);
1552 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1554 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1555 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1557 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1558 msg_param.connection.buffering = player->streamer->buffering_percent;
1559 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1561 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1564 msg_param.connection.buffering = player->streamer->buffering_percent;
1565 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1568 MMPLAYER_CMD_UNLOCK(player);
1576 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1578 mmplayer_gst_element_t *mainbin;
1579 GstState oldstate = GST_STATE_NULL;
1580 GstState newstate = GST_STATE_NULL;
1581 GstState pending = GST_STATE_NULL;
1584 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1586 mainbin = player->pipeline->mainbin;
1588 /* we only handle messages from pipeline */
1589 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1592 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pending);
1594 LOGD("state changed [%s] : %s ---> %s final : %s",
1595 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1596 gst_element_state_get_name((GstState)oldstate),
1597 gst_element_state_get_name((GstState)newstate),
1598 gst_element_state_get_name((GstState)pending));
1600 if (newstate == GST_STATE_PLAYING) {
1601 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1603 int retVal = MM_ERROR_NONE;
1604 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1606 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1608 if (MM_ERROR_NONE != retVal)
1609 LOGE("failed to seek pending position. just keep staying current position.");
1611 player->pending_seek.is_pending = false;
1615 if (oldstate == newstate) {
1616 LOGD("pipeline reports state transition to old state");
1621 case GST_STATE_PAUSED:
1623 gboolean prepare_async = FALSE;
1625 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1626 // managed prepare async case
1627 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1628 LOGD("checking prepare mode for async transition - %d", prepare_async);
1631 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1632 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1634 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1635 _mm_player_streaming_set_content_bitrate(player->streamer,
1636 player->total_maximum_bitrate, player->total_bitrate);
1638 if (player->pending_seek.is_pending) {
1639 LOGW("trying to do pending seek");
1640 MMPLAYER_CMD_LOCK(player);
1641 __mmplayer_gst_pending_seek(player);
1642 MMPLAYER_CMD_UNLOCK(player);
1648 case GST_STATE_PLAYING:
1650 if (MMPLAYER_IS_STREAMING(player)) {
1651 // managed prepare async case when buffering is completed
1652 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1653 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1654 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1655 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1657 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1659 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1660 if (player->streamer->buffering_percent < 100) {
1662 MMMessageParamType msg_param = {0, };
1663 LOGW("Posting Buffering Completed Message to Application !!!");
1665 msg_param.connection.buffering = 100;
1666 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1671 if (player->gapless.stream_changed) {
1672 _mmplayer_update_content_attrs(player, ATTR_ALL);
1673 player->gapless.stream_changed = FALSE;
1676 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1677 player->seek_state = MMPLAYER_SEEK_NONE;
1678 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1682 case GST_STATE_VOID_PENDING:
1683 case GST_STATE_NULL:
1684 case GST_STATE_READY:
1694 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1696 const gchar *structure_name;
1697 gint count = 0, idx = 0;
1700 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1702 if (gst_message_get_structure(msg) == NULL)
1705 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1706 if (!structure_name)
1709 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1711 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1712 const GValue *var_info = NULL;
1714 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1715 if (var_info != NULL) {
1716 if (player->adaptive_info.var_list)
1717 g_list_free_full(player->adaptive_info.var_list, g_free);
1719 /* share addr or copy the list */
1720 player->adaptive_info.var_list =
1721 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1723 count = g_list_length(player->adaptive_info.var_list);
1725 stream_variant_t *temp = NULL;
1727 /* print out for debug */
1728 LOGD("num of variant_info %d", count);
1729 for (idx = 0; idx < count; idx++) {
1730 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1732 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1738 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1739 gint num_buffers = 0;
1740 gint extra_num_buffers = 0;
1742 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1743 LOGD("video_num_buffers : %d", num_buffers);
1744 mm_player_set_attribute((MMHandleType)player, NULL,
1745 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1748 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1749 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1750 mm_player_set_attribute((MMHandleType)player, NULL,
1751 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1756 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1757 _mmplayer_track_update_text_attr_info(player, msg);
1759 /* custom message */
1760 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1761 MMMessageParamType msg_param = {0,};
1762 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1763 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1766 /* custom message for RTSP attribute :
1767 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1768 sdp which has contents info is received when rtsp connection is opened.
1769 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1770 if (!strcmp(structure_name, "rtspsrc_properties")) {
1771 g_autofree gchar *audio_codec = NULL;
1772 g_autofree gchar *video_codec = NULL;
1773 g_autofree gchar *video_frame_size = NULL;
1775 gst_structure_get(gst_message_get_structure(msg),
1776 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1777 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1778 player->streaming_type = _mmplayer_get_stream_service_type(player);
1780 gst_structure_get(gst_message_get_structure(msg),
1781 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1782 LOGD("rtsp_audio_codec : %s", audio_codec);
1784 mm_player_set_attribute((MMHandleType)player, NULL,
1785 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1787 gst_structure_get(gst_message_get_structure(msg),
1788 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1789 LOGD("rtsp_video_codec : %s", video_codec);
1791 mm_player_set_attribute((MMHandleType)player, NULL,
1792 "content_video_codec", video_codec, strlen(video_codec), NULL);
1794 gst_structure_get(gst_message_get_structure(msg),
1795 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1796 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1797 if (video_frame_size) {
1798 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1799 mm_player_set_attribute((MMHandleType)player, NULL,
1800 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1801 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1803 g_strfreev(res_str);
1812 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1814 mmplayer_gst_element_t *mainbin;
1817 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1819 mainbin = player->pipeline->mainbin;
1821 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1823 /* we only handle messages from pipeline */
1824 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1827 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1828 if (player->is_external_subtitle_present)
1829 _mmplayer_sync_subtitle_pipeline(player);
1831 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1832 player->seek_state = MMPLAYER_SEEK_NONE;
1833 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1834 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1835 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1836 LOGD("sync %s state(%s) with parent state(%s)",
1837 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1838 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1839 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1841 /* In case of streaming, pause is required before finishing seeking by buffering.
1842 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1843 Because the buffering state is controlled according to the state transition for force resume,
1844 the decodebin state should be paused as player state. */
1845 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1848 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1849 (player->streamer) &&
1850 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1851 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1852 GstQuery *query = NULL;
1853 gboolean busy = FALSE;
1856 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1857 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1858 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1859 gst_query_parse_buffering_percent(query, &busy, &percent);
1860 gst_query_unref(query);
1862 LOGD("buffered percent(%s): %d",
1863 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1867 __mmplayer_handle_buffering_playback(player);
1870 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1880 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1882 GValue val = { 0, };
1884 guint indent = GPOINTER_TO_UINT(user_data);
1886 if (!gst_tag_list_copy_value(&val, tags, tag))
1889 if (G_VALUE_HOLDS_STRING(&val))
1890 str = g_value_dup_string(&val);
1892 str = gst_value_serialize(&val);
1894 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1896 g_value_unset(&val);
1901 __mmplayer_dump_collection(GstStreamCollection * collection)
1905 GstTagList *tags = NULL;
1907 GstCaps *caps = NULL;
1909 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1910 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1911 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1912 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1913 gst_stream_get_stream_flags(stream));
1914 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1916 caps = gst_stream_get_caps(stream);
1918 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1919 gst_caps_unref(caps);
1923 tags = gst_stream_get_tags(stream);
1926 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1927 gst_tag_list_unref(tags);
1934 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1935 GstStream *stream, GParamSpec *pspec, gpointer data)
1937 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1938 gst_stream_get_stream_id(stream), pspec->name, collection);
1939 if (g_str_equal(pspec->name, "caps")) {
1940 GstCaps *caps = gst_stream_get_caps(stream);
1941 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1942 gst_caps_unref(caps);
1946 if (g_str_equal (pspec->name, "tags")) {
1947 GstTagList *tags = gst_stream_get_tags(stream);
1950 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1951 gst_tag_list_unref(tags);
1958 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1960 mmplayer_t *player = (mmplayer_t *)(data);
1962 MMPLAYER_RETURN_IF_FAIL(player);
1963 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1965 switch (GST_MESSAGE_TYPE(msg)) {
1966 case GST_MESSAGE_UNKNOWN:
1967 LOGD("unknown message received");
1970 case GST_MESSAGE_EOS:
1971 LOGD("GST_MESSAGE_EOS received");
1972 __mmplayer_gst_handle_eos_message(player, msg);
1975 case GST_MESSAGE_ERROR:
1976 _mmplayer_set_reconfigure_state(player, FALSE);
1977 __mmplayer_gst_handle_error_message(player, msg);
1980 case GST_MESSAGE_WARNING:
1983 GError *error = NULL;
1985 gst_message_parse_warning(msg, &error, &debug);
1987 LOGD("warning : %s", error->message);
1988 LOGD("debug : %s", debug);
1990 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1992 MMPLAYER_FREEIF(debug);
1993 g_error_free(error);
1997 case GST_MESSAGE_TAG:
1999 LOGD("GST_MESSAGE_TAG");
2000 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2001 LOGW("failed to extract tags from gstmessage");
2005 case GST_MESSAGE_BUFFERING:
2006 __mmplayer_gst_handle_buffering_message(player, msg);
2009 case GST_MESSAGE_STATE_CHANGED:
2010 __mmplayer_gst_handle_state_message(player, msg);
2013 case GST_MESSAGE_CLOCK_LOST:
2015 GstClock *clock = NULL;
2016 gboolean need_new_clock = FALSE;
2018 gst_message_parse_clock_lost(msg, &clock);
2019 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2021 if (!player->videodec_linked)
2022 need_new_clock = TRUE;
2023 else if (!player->ini.use_system_clock)
2024 need_new_clock = TRUE;
2026 if (need_new_clock) {
2027 LOGD("Provide clock is TRUE, do pause->resume");
2028 _mmplayer_gst_pause(player, FALSE);
2029 _mmplayer_gst_resume(player, FALSE);
2034 case GST_MESSAGE_NEW_CLOCK:
2036 GstClock *clock = NULL;
2037 gst_message_parse_new_clock(msg, &clock);
2038 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2042 case GST_MESSAGE_ELEMENT:
2043 __mmplayer_gst_handle_element_message(player, msg);
2046 case GST_MESSAGE_DURATION_CHANGED:
2048 LOGD("GST_MESSAGE_DURATION_CHANGED");
2049 if (!__mmplayer_gst_handle_duration(player, msg))
2050 LOGW("failed to update duration");
2054 case GST_MESSAGE_ASYNC_START:
2055 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2058 case GST_MESSAGE_ASYNC_DONE:
2059 __mmplayer_gst_handle_async_done_message(player, msg);
2061 case GST_MESSAGE_STREAM_COLLECTION:
2063 GstStreamCollection *collection = NULL;
2064 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2066 gst_message_parse_stream_collection(msg, &collection);
2068 __mmplayer_dump_collection(collection);
2069 if (player->collection && player->stream_notify_id) {
2070 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2071 player->stream_notify_id = 0;
2073 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2074 if (player->collection) {
2075 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2076 (GCallback)__mmplayer_stream_notify_cb, player);
2078 gst_object_unref(collection);
2081 case GST_MESSAGE_STREAMS_SELECTED:
2083 GstStreamCollection *collection = NULL;
2084 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2086 gst_message_parse_streams_selected(msg, &collection);
2088 guint len = gst_message_streams_selected_get_size(msg);
2089 for (guint i = 0; i < len; i++) {
2090 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2091 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2092 gst_stream_get_stream_type(stream));
2093 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2094 LOGD("not supported track type");
2095 gst_object_unref(stream);
2098 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2099 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2100 int stream_index = INVALID_TRACK_INDEX;
2101 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2102 player->track[type].active_track_index = stream_index;
2103 LOGD("selected this stream, update active idx : %d",
2104 player->track[type].active_track_index);
2107 gst_object_unref(stream);
2109 gst_object_unref(collection);
2114 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2115 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2116 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2117 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2118 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2119 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2120 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2121 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2122 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2123 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2124 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2125 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2126 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2127 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2128 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2135 /* should not call 'gst_message_unref(msg)' */
2139 static GstBusSyncReply
2140 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2142 mmplayer_t *player = (mmplayer_t *)data;
2143 GstBusSyncReply reply = GST_BUS_DROP;
2145 if (!(player->pipeline && player->pipeline->mainbin)) {
2146 LOGE("player pipeline handle is null");
2147 return GST_BUS_PASS;
2150 if (!__mmplayer_gst_check_useful_message(player, message)) {
2151 gst_message_unref(message);
2152 return GST_BUS_DROP;
2155 switch (GST_MESSAGE_TYPE(message)) {
2156 case GST_MESSAGE_TAG:
2157 __mmplayer_gst_extract_tag_from_msg(player, message);
2161 GstTagList *tags = NULL;
2163 gst_message_parse_tag(message, &tags);
2165 LOGE("TAGS received from element \"%s\".",
2166 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2168 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2169 gst_tag_list_unref(tags);
2177 case GST_MESSAGE_DURATION_CHANGED:
2178 __mmplayer_gst_handle_duration(player, message);
2180 case GST_MESSAGE_ELEMENT:
2182 const gchar *klass = NULL;
2183 klass = gst_element_factory_get_metadata
2184 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2185 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2186 reply = GST_BUS_PASS;
2189 __mmplayer_gst_handle_element_message(player, message);
2192 case GST_MESSAGE_ASYNC_DONE:
2193 /* NOTE:Don't call gst_callback directly
2194 * because previous frame can be showed even though this message is received for seek.
2197 reply = GST_BUS_PASS;
2201 if (reply == GST_BUS_DROP)
2202 gst_message_unref(message);
2208 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2210 GstElement *appsrc = element;
2211 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2212 GstBuffer *buffer = NULL;
2213 GstFlowReturn ret = GST_FLOW_OK;
2216 MMPLAYER_RETURN_IF_FAIL(element);
2217 MMPLAYER_RETURN_IF_FAIL(buf);
2219 buffer = gst_buffer_new();
2221 if (buf->offset < 0 || buf->len < 0) {
2222 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2226 if (buf->offset >= buf->len) {
2227 LOGD("call eos appsrc");
2228 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2232 if (buf->len - buf->offset < size)
2233 len = buf->len - buf->offset;
2235 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2236 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2237 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2240 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2242 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2248 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2250 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2252 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2254 buf->offset = (int)size;
2260 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2262 mmplayer_t *player = (mmplayer_t *)user_data;
2263 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2264 MMMessageParamType msg_param = {0,};
2265 guint64 current_level_bytes = 0;
2267 MMPLAYER_RETURN_IF_FAIL(player);
2269 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2270 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2271 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2272 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2274 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2278 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2280 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2282 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2283 msg_param.buffer_status.stream_type = stream_type;
2284 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2285 msg_param.buffer_status.bytes = current_level_bytes;
2287 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2291 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2293 mmplayer_t *player = (mmplayer_t *)user_data;
2294 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2295 MMMessageParamType msg_param = {0,};
2296 guint64 current_level_bytes = 0;
2298 MMPLAYER_RETURN_IF_FAIL(player);
2300 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2301 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2302 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2303 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2305 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2309 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2311 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2313 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2314 msg_param.buffer_status.stream_type = stream_type;
2315 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2316 msg_param.buffer_status.bytes = current_level_bytes;
2318 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2322 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2324 mmplayer_t *player = (mmplayer_t *)user_data;
2325 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2326 MMMessageParamType msg_param = {0,};
2328 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2330 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2331 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2332 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2333 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2335 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2339 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2341 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2342 msg_param.seek_data.stream_type = stream_type;
2343 msg_param.seek_data.offset = position;
2345 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2351 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2353 #define MAX_LEN_NAME 20
2355 gboolean ret = FALSE;
2356 GstPad *sinkpad = NULL;
2357 gchar *prefix = NULL;
2358 gchar dec_name[MAX_LEN_NAME] = {0, };
2359 main_element_id_e elem_id = MMPLAYER_M_NUM;
2361 mmplayer_gst_element_t *mainbin = NULL;
2362 GstElement *decodebin = NULL;
2363 GstCaps *dec_caps = NULL;
2367 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2369 player->pipeline->mainbin, FALSE);
2370 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2372 mainbin = player->pipeline->mainbin;
2374 case MM_PLAYER_STREAM_TYPE_AUDIO:
2376 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2378 case MM_PLAYER_STREAM_TYPE_VIDEO:
2380 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2383 LOGE("invalid type %d", type);
2387 if (mainbin[elem_id].gst) {
2388 LOGE("elem(%d) is already created", elem_id);
2392 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2394 /* create decodebin */
2395 decodebin = gst_element_factory_make("decodebin", dec_name);
2397 LOGE("failed to create %s", dec_name);
2401 /* raw pad handling signal */
2402 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2403 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2405 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2406 before looking for any elements that can handle that stream.*/
2407 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2408 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2410 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2411 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2412 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2414 /* This signal is emitted when a element is added to the bin.*/
2415 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2416 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2418 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2419 LOGE("failed to add new decodebin");
2423 dec_caps = gst_pad_query_caps(srcpad, NULL);
2426 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2428 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2429 gst_caps_unref(dec_caps);
2432 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2434 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2435 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2438 gst_object_unref(GST_OBJECT(sinkpad));
2440 gst_element_sync_state_with_parent(decodebin);
2442 mainbin[elem_id].id = elem_id;
2443 mainbin[elem_id].gst = decodebin;
2450 gst_object_unref(GST_OBJECT(sinkpad));
2453 gst_element_set_state(decodebin, GST_STATE_NULL);
2454 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2455 gst_object_unref(decodebin);
2463 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2465 #define MAX_LEN_NAME 20
2466 mmplayer_gst_element_t *mainbin = NULL;
2467 gchar *prefix = NULL;
2468 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2470 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2471 GstElement *src = NULL, *queue = NULL;
2472 GstPad *srcpad = NULL;
2475 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2476 player->pipeline->mainbin, FALSE);
2478 mainbin = player->pipeline->mainbin;
2480 LOGD("type(%d) path is creating", type);
2482 case MM_PLAYER_STREAM_TYPE_AUDIO:
2484 if (mainbin[MMPLAYER_M_SRC].gst)
2485 src_id = MMPLAYER_M_2ND_SRC;
2487 src_id = MMPLAYER_M_SRC;
2488 queue_id = MMPLAYER_M_A_BUFFER;
2490 case MM_PLAYER_STREAM_TYPE_VIDEO:
2492 src_id = MMPLAYER_M_SRC;
2493 queue_id = MMPLAYER_M_V_BUFFER;
2495 case MM_PLAYER_STREAM_TYPE_TEXT:
2496 prefix = "subtitle";
2497 src_id = MMPLAYER_M_SUBSRC;
2498 queue_id = MMPLAYER_M_S_BUFFER;
2501 LOGE("invalid type %d", type);
2505 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2506 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2509 src = gst_element_factory_make("appsrc", src_name);
2511 LOGF("failed to create %s", src_name);
2515 mainbin[src_id].id = src_id;
2516 mainbin[src_id].gst = src;
2518 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2519 "caps", caps, NULL);
2521 /* size of many video frames are larger than default blocksize as 4096 */
2522 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2523 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2525 if (player->media_stream_buffer_max_size[type] > 0)
2526 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2528 if (player->media_stream_buffer_min_percent[type] > 0)
2529 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2531 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2532 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2534 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2535 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2536 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2537 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2538 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2539 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2542 queue = gst_element_factory_make("queue2", queue_name);
2544 LOGE("failed to create %s", queue_name);
2547 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2549 mainbin[queue_id].id = queue_id;
2550 mainbin[queue_id].gst = queue;
2552 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2553 LOGE("failed to add src");
2557 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2558 LOGE("failed to add queue");
2562 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2563 LOGE("failed to link src and queue");
2567 /* create decoder */
2568 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2570 LOGE("failed to get srcpad of queue");
2574 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2575 _mmplayer_gst_create_decoder(player, srcpad, caps);
2577 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2578 LOGE("failed to create decoder");
2579 gst_object_unref(GST_OBJECT(srcpad));
2583 gst_object_unref(GST_OBJECT(srcpad));
2587 if (mainbin[src_id].gst) {
2588 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2589 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2590 gst_object_unref(mainbin[src_id].gst);
2591 mainbin[src_id].gst = NULL;
2594 if (mainbin[queue_id].gst) {
2595 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2596 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2597 gst_object_unref(mainbin[queue_id].gst);
2598 mainbin[queue_id].gst = NULL;
2605 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2607 GstPad *sinkpad = NULL;
2608 GstCaps *caps = NULL;
2609 GstElement *new_element = NULL;
2610 GstStructure *str = NULL;
2611 const gchar *name = NULL;
2613 mmplayer_t *player = (mmplayer_t *)data;
2617 MMPLAYER_RETURN_IF_FAIL(element && pad);
2618 MMPLAYER_RETURN_IF_FAIL(player &&
2620 player->pipeline->mainbin);
2622 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2623 * num_dynamic_pad will decreased after creating a sinkbin.
2625 player->num_dynamic_pad++;
2626 LOGD("stream count inc : %d", player->num_dynamic_pad);
2628 caps = gst_pad_query_caps(pad, NULL);
2629 MMPLAYER_CHECK_NULL(caps);
2631 str = gst_caps_get_structure(caps, 0);
2632 name = gst_structure_get_string(str, "media");
2634 LOGE("cannot get mimetype from structure.");
2638 if (strstr(name, "video")) {
2640 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2642 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2643 if (player->v_stream_caps) {
2644 gst_caps_unref(player->v_stream_caps);
2645 player->v_stream_caps = NULL;
2648 new_element = gst_element_factory_make("fakesink", NULL);
2649 player->num_dynamic_pad--;
2654 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2655 LOGE("failed to autoplug for caps");
2659 gst_caps_unref(caps);
2664 /* execute new_element if created*/
2666 LOGD("adding new element to pipeline");
2668 /* set state to READY before add to bin */
2669 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2671 /* add new element to the pipeline */
2672 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2673 LOGE("failed to add autoplug element to bin");
2677 /* get pad from element */
2678 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2680 LOGE("failed to get sinkpad from autoplug element");
2685 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2686 LOGE("failed to link autoplug element");
2690 gst_object_unref(sinkpad);
2693 /* run. setting PLAYING here since streaming source is live source */
2694 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2698 gst_caps_unref(caps);
2704 STATE_CHANGE_FAILED:
2706 /* FIXIT : take care if new_element has already added to pipeline */
2708 gst_object_unref(GST_OBJECT(new_element));
2711 gst_object_unref(GST_OBJECT(sinkpad));
2714 gst_caps_unref(caps);
2716 /* FIXIT : how to inform this error to MSL ????? */
2717 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2718 * then post an error to application
2723 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2725 mmplayer_t *player = (mmplayer_t *)data;
2729 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2730 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2731 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2732 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2734 * [1] audio and video will be dumped with filesink.
2735 * [2] autoplugging is done by just using pad caps.
2736 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2737 * and the video will be dumped via filesink.
2739 if (player->num_dynamic_pad == 0) {
2740 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2742 if (!_mmplayer_gst_remove_fakesink(player,
2743 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2744 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2745 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2746 * source element are not same. To overcome this situation, this function will called
2747 * several places and several times. Therefore, this is not an error case.
2752 /* create dot before error-return. for debugging */
2753 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2755 player->no_more_pad = TRUE;
2761 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2763 GstElement *element = NULL;
2764 gchar *user_agent = NULL;
2765 MMHandleType attrs = 0;
2768 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2770 /* get profile attribute */
2771 attrs = MMPLAYER_GET_ATTRS(player);
2773 LOGE("failed to get content attribute");
2777 element = gst_element_factory_make("rtspsrc", "rtsp source");
2779 LOGE("failed to create rtspsrc element");
2784 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2786 SECURE_LOGD("user_agent : %s", user_agent);
2788 /* setting property to streaming source */
2789 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2791 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2793 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2794 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2795 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2796 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2802 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2804 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2806 mmplayer_t *player = (mmplayer_t *)data;
2807 MMHandleType attrs = 0;
2808 gchar *user_agent, *cookies, **cookie_list;
2809 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2810 user_agent = cookies = NULL;
2814 MMPLAYER_RETURN_IF_FAIL(player);
2816 LOGD("source element %s", GST_ELEMENT_NAME(source));
2818 attrs = MMPLAYER_GET_ATTRS(player);
2820 LOGE("failed to get content attribute");
2824 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2825 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2827 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2828 http_timeout = player->ini.http_timeout;
2830 SECURE_LOGD("cookies : %s", cookies);
2831 SECURE_LOGD("user_agent : %s", user_agent);
2832 LOGD("timeout : %d", http_timeout);
2834 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2836 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2837 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2838 g_strfreev(cookie_list);
2842 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2848 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2850 mmplayer_t *player = (mmplayer_t *)data;
2851 gchar *user_agent = NULL;
2852 MMHandleType attrs = 0;
2855 MMPLAYER_RETURN_IF_FAIL(player);
2857 attrs = MMPLAYER_GET_ATTRS(player);
2859 LOGE("failed to get content attribute");
2863 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2865 SECURE_LOGD("user_agent : %s", user_agent);
2868 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2874 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2876 mmplayer_t *player = (mmplayer_t *)data;
2877 GstElement *source = NULL;
2880 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2882 g_object_get(orig, pspec->name, &source, NULL);
2884 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2885 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2887 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2888 __mmplayer_http_src_setup(source, data);
2889 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2890 __mmplayer_rtsp_src_setup(source, data);
2891 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2892 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2893 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2894 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2895 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2897 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2898 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2899 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2900 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2902 gst_object_unref (source);
2908 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2909 GstStream * stream, gpointer data)
2911 #define RET_SELECT 1
2913 #define RET_DEPENDS_ON_DECODEBIN -1
2915 GstStreamType stype = gst_stream_get_stream_type(stream);
2916 mmplayer_t *player = (mmplayer_t *)data;
2917 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2918 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2919 g_autofree gchar *caps_str = NULL;
2920 GstStructure *caps_structure = NULL;
2921 int stream_index = INVALID_TRACK_INDEX;
2922 int ret = MM_ERROR_NONE;
2924 LOGD("Stream type %s flags 0x%x",
2925 gst_stream_type_get_name(stype),
2926 gst_stream_get_stream_flags(stream));
2927 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2929 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
2932 caps_str = gst_caps_to_string(caps);
2933 caps_structure = gst_caps_get_structure(caps, 0);
2934 const gchar *mime = gst_structure_get_name(caps_structure);
2936 LOGD(" caps: %s", caps_str);
2938 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2939 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2940 LOGW("skip [%s] by unsupported codec keyword [%s]",
2941 mime, player->ini.unsupported_codec_keyword[idx]);
2943 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2947 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2948 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2949 LOGD("No caps info, depends on decodebin");
2950 _mmplayer_track_update_stream(player, type, stream);
2951 return RET_DEPENDS_ON_DECODEBIN;
2954 LOGD("No caps info, skip it");
2959 case GST_STREAM_TYPE_AUDIO:
2961 if (caps_structure) {
2962 gint samplerate = 0;
2965 gst_structure_get_int(caps_structure, "rate", &samplerate);
2966 gst_structure_get_int(caps_structure, "channels", &channels);
2967 if (samplerate == 0 && channels > 0) {
2968 LOGW("Skip corrupted audio stream");
2972 if (g_strrstr(caps_str, "mobile-xmf"))
2973 mm_player_set_attribute((MMHandleType)player, NULL,
2974 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2978 case GST_STREAM_TYPE_VIDEO:
2980 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2981 LOGD("do not support muti track video");
2985 // FIXME: it cause block during preparing
2986 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2989 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2990 /* don't make video because of not required */
2991 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2992 (!player->set_mode.video_export)) {
2993 LOGD("no need video decoding, skip video stream");
2998 if (caps_structure) {
3001 gst_structure_get_int(caps_structure, "width", &width);
3003 if (player->v_stream_caps) {
3004 gst_caps_unref(player->v_stream_caps);
3005 player->v_stream_caps = NULL;
3008 player->v_stream_caps = gst_caps_copy(caps);
3009 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3014 case GST_STREAM_TYPE_TEXT:
3017 LOGW("Skip not supported stream type");
3021 _mmplayer_track_update_stream(player, type, stream);
3023 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3025 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3026 (ret == MM_ERROR_NONE)) {
3027 player->track[type].active_track_index = stream_index;
3028 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3029 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3030 _mmplayer_set_audio_attrs(player, caps);
3034 if (player->track[type].active_track_index == stream_index) {
3035 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3039 LOGD("Skip stream");
3044 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3045 GstStream * stream, gpointer data)
3047 mmplayer_t *player = (mmplayer_t *)data;
3048 GstStreamType stype = gst_stream_get_stream_type(stream);
3051 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3053 LOGD("stream type %s", gst_stream_type_get_name(stype));
3055 /* public does not support audio hw decoder at the moment */
3057 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3058 LOGW("video decoder resource is already acquired, skip it.");
3062 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3063 LOGE("failed to acquire video decoder resource");
3066 player->interrupted_by_resource = FALSE;
3072 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3074 GstIterator *iter = NULL;
3075 GValue item = {0, };
3076 GstElement *ch_element = NULL;
3077 GstElementFactory *ch_factory = NULL;
3080 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3082 iter = gst_bin_iterate_recurse(bin);
3083 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3085 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3086 ch_element = g_value_get_object(&item);
3087 ch_factory = gst_element_get_factory(ch_element);
3088 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3089 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3090 LOGD("Find %s element", element_name);
3094 g_value_reset(&item);
3096 gst_iterator_free(iter);
3102 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3104 mmplayer_t *player = (mmplayer_t *)data;
3106 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3108 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3109 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3110 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3112 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3113 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3114 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3117 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3119 mmplayer_t *player = (mmplayer_t *)data;
3120 int video_codec_type = 0;
3121 int audio_codec_type = 0;
3123 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3125 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3126 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3128 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3130 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3131 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3132 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3133 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3135 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3136 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3140 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3142 gchar *factory_name = NULL;
3143 mmplayer_t *player = (mmplayer_t *)data;
3146 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3148 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3150 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3152 if (g_strrstr(factory_name, "urisourcebin")) {
3153 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3155 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3157 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3159 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3161 LOGW("failed to find decodebin3");
3163 } else if (g_strrstr(factory_name, "parsebin")) {
3164 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3165 __mmplayer_parsebin_setup(GST_BIN(element), data);
3167 _mmplayer_gst_element_added(child, element, data);
3172 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3176 MMPLAYER_RETURN_IF_FAIL(player);
3177 MMPLAYER_RETURN_IF_FAIL(removed_element);
3179 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3181 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3182 GList *node = player->signals[type];
3184 GList *next_node = node->next;
3185 mmplayer_signal_item_t *item = node->data;
3186 if (item && item->obj == G_OBJECT(removed_element)) {
3187 player->signals[type] = g_list_delete_link(player->signals[type], node);
3188 MMPLAYER_FREEIF(item);
3198 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3200 mmplayer_t *player = (mmplayer_t *)data;
3204 MMPLAYER_RETURN_IF_FAIL(player);
3206 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3208 __mmplayer_delete_signal_connection(player, element);
3214 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3216 GstElement *uridecodebin3 = NULL;
3219 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3221 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3222 if (!uridecodebin3) {
3223 LOGE("failed to create uridecodebin3");
3228 SECURE_LOGD("uri : %s", player->profile.uri);
3230 /* setting property to streaming source */
3231 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3232 "message-forward", TRUE,
3233 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3234 "use-buffering", TRUE, NULL);
3236 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3237 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3239 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3240 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3242 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3245 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3248 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3251 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3252 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3254 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3255 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3257 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3258 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3260 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3261 LOGW("[DASH] this is still experimental feature");
3264 return uridecodebin3;
3268 __mmplayer_gst_make_http_src(mmplayer_t *player)
3270 #define MAX_RETRY_COUNT 10
3271 GstElement *element = NULL;
3272 MMHandleType attrs = 0;
3273 gchar *user_agent, *cookies, **cookie_list;
3274 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3276 user_agent = cookies = NULL;
3280 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3282 /* get profile attribute */
3283 attrs = MMPLAYER_GET_ATTRS(player);
3285 LOGE("failed to get content attribute");
3289 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3291 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3293 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3298 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3299 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3301 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3302 http_timeout = player->ini.http_timeout;
3305 SECURE_LOGD("location : %s", player->profile.uri);
3306 SECURE_LOGD("cookies : %s", cookies);
3307 SECURE_LOGD("user_agent : %s", user_agent);
3308 LOGD("timeout : %d", http_timeout);
3310 /* setting property to streaming source */
3311 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3312 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3313 "retries", MAX_RETRY_COUNT, NULL);
3315 /* parsing cookies */
3316 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3317 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3318 g_strfreev(cookie_list);
3322 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3324 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3325 LOGW("[DASH] this is still experimental feature");
3332 __mmplayer_gst_make_file_src(mmplayer_t *player)
3334 GstElement *element = NULL;
3337 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3339 LOGD("using filesrc for 'file://' handler");
3340 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3341 LOGE("failed to get storage info");
3345 element = gst_element_factory_make("filesrc", "source");
3347 LOGE("failed to create filesrc");
3351 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3358 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3360 mmplayer_t *player = (mmplayer_t *)data;
3362 g_return_val_if_fail(player, FALSE);
3363 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3364 gst_message_ref(msg);
3366 g_mutex_lock(&player->bus_msg_q_lock);
3367 g_queue_push_tail(player->bus_msg_q, msg);
3368 g_mutex_unlock(&player->bus_msg_q_lock);
3370 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3371 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3372 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3376 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3378 mmplayer_t *player = (mmplayer_t *)(data);
3379 GstMessage *msg = NULL;
3382 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3384 player->pipeline->mainbin &&
3385 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3388 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3390 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3391 while (!player->bus_msg_thread_exit) {
3392 g_mutex_lock(&player->bus_msg_q_lock);
3393 msg = g_queue_pop_head(player->bus_msg_q);
3394 g_mutex_unlock(&player->bus_msg_q_lock);
3396 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3399 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3400 /* handle the gst msg */
3401 __mmplayer_gst_bus_msg_callback(msg, player);
3402 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3403 gst_message_unref(msg);
3406 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3413 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3415 gint64 dur_nsec = 0;
3416 gint64 pos_nsec = 0;
3419 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3421 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3422 return MM_ERROR_NONE;
3424 /* NOTE : duration cannot be zero except live streaming.
3425 * Since some element could have some timing problem with querying duration, try again.
3427 if (player->duration == 0) {
3428 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3429 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3430 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3431 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3432 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3433 player->pending_seek.is_pending = true;
3434 player->pending_seek.pos = position;
3435 player->seek_state = MMPLAYER_SEEK_NONE;
3436 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3437 return MM_ERROR_PLAYER_NO_OP;
3439 player->seek_state = MMPLAYER_SEEK_NONE;
3440 return MM_ERROR_PLAYER_SEEK;
3443 player->duration = dur_nsec;
3446 if (player->duration > 0 && player->duration < position) {
3447 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3448 return MM_ERROR_INVALID_ARGUMENT;
3451 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3452 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3453 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3454 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3455 player->seek_state = MMPLAYER_SEEK_NONE;
3456 return MM_ERROR_PLAYER_NO_OP;
3461 return MM_ERROR_NONE;
3465 __mmplayer_gst_check_seekable(mmplayer_t *player)
3467 GstQuery *query = NULL;
3468 gboolean seekable = FALSE;
3470 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3474 query = gst_query_new_seeking(GST_FORMAT_TIME);
3475 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3476 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3477 gst_query_unref(query);
3480 LOGW("non-seekable content");
3481 player->seek_state = MMPLAYER_SEEK_NONE;
3485 LOGW("failed to get seeking query");
3486 gst_query_unref(query); /* keep seeking operation */
3493 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3495 GstState element_state = GST_STATE_VOID_PENDING;
3496 GstState element_pending_state = GST_STATE_VOID_PENDING;
3497 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3501 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3502 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3504 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3507 ret = gst_element_set_state(element, state);
3508 if (ret == GST_STATE_CHANGE_FAILURE) {
3509 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3511 /* dump state of all element */
3512 _mmplayer_dump_pipeline_state(player);
3514 return MM_ERROR_PLAYER_INTERNAL;
3517 /* return here so state transition to be done in async mode */
3519 LOGD("async state transition. not waiting for state complete.");
3520 return MM_ERROR_NONE;
3523 /* wait for state transition */
3524 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3525 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3526 LOGE("failed to change [%s] element state to [%s] within %d sec",
3527 GST_ELEMENT_NAME(element),
3528 gst_element_state_get_name(state), timeout);
3530 LOGE(" [%s] state : %s pending : %s",
3531 GST_ELEMENT_NAME(element),
3532 gst_element_state_get_name(element_state),
3533 gst_element_state_get_name(element_pending_state));
3535 /* dump state of all element */
3536 _mmplayer_dump_pipeline_state(player);
3538 return MM_ERROR_PLAYER_INTERNAL;
3541 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3545 return MM_ERROR_NONE;
3549 _mmplayer_gst_start(mmplayer_t *player)
3551 int ret = MM_ERROR_NONE;
3552 gboolean async = FALSE;
3556 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3558 /* NOTE : if SetPosition was called before Start. do it now
3559 * streaming doesn't support it. so it should be always sync
3560 * !!create one more api to check if there is pending seek rather than checking variables
3562 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3563 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3564 ret = _mmplayer_gst_pause(player, FALSE);
3565 if (ret != MM_ERROR_NONE) {
3566 LOGE("failed to set state to PAUSED for pending seek");
3570 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3571 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3572 LOGW("failed to seek pending position. starting from the begin of content");
3575 LOGD("current state before doing transition");
3576 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3577 MMPLAYER_PRINT_STATE(player);
3579 /* set pipeline state to PLAYING */
3580 ret = _mmplayer_gst_set_state(player,
3581 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3582 if (ret != MM_ERROR_NONE) {
3583 LOGE("failed to set state to PLAYING");
3587 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3589 /* generating debug info before returning error */
3590 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3598 _mmplayer_gst_stop(mmplayer_t *player)
3600 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3601 MMHandleType attrs = 0;
3602 gboolean rewind = FALSE;
3604 int ret = MM_ERROR_NONE;
3608 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3609 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3611 LOGD("current state before doing transition");
3612 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3613 MMPLAYER_PRINT_STATE(player);
3615 attrs = MMPLAYER_GET_ATTRS(player);
3617 LOGE("cannot get content attribute");
3618 return MM_ERROR_PLAYER_INTERNAL;
3621 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3622 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3624 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3625 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3628 if (player->es_player_push_mode)
3629 /* disable the async state transition because there could be no data in the pipeline */
3630 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3633 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3635 if (player->es_player_push_mode) {
3636 /* enable the async state transition as default operation */
3637 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3640 /* return if set_state has failed */
3641 if (ret != MM_ERROR_NONE) {
3642 LOGE("failed to set state.");
3648 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3649 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3650 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3651 LOGW("failed to rewind");
3652 ret = MM_ERROR_PLAYER_SEEK;
3657 player->sent_bos = FALSE;
3659 if (player->es_player_push_mode) //for cloudgame
3662 /* wait for seek to complete */
3663 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3664 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3665 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3667 LOGE("fail to stop player.");
3668 ret = MM_ERROR_PLAYER_INTERNAL;
3669 _mmplayer_dump_pipeline_state(player);
3672 /* generate dot file if enabled */
3673 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3681 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3683 int ret = MM_ERROR_NONE;
3687 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3688 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3690 LOGD("current state before doing transition");
3691 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3692 MMPLAYER_PRINT_STATE(player);
3694 /* set pipeline status to PAUSED */
3695 ret = _mmplayer_gst_set_state(player,
3696 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3701 if (ret != MM_ERROR_NONE) {
3702 GstMessage *msg = NULL;
3703 GTimer *timer = NULL;
3704 gdouble MAX_TIMEOUT_SEC = 3;
3706 LOGE("failed to set state to PAUSED");
3708 if (!player->bus_watcher) {
3709 LOGE("there is no bus msg thread. pipeline is shutting down.");
3713 if (player->msg_posted) {
3714 LOGE("error msg is already posted.");
3718 timer = g_timer_new();
3719 g_timer_start(timer);
3721 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3724 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3726 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3727 GError *error = NULL;
3729 /* parse error code */
3730 gst_message_parse_error(msg, &error, NULL);
3732 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3733 /* Note : the streaming error from the streaming source is handled
3734 * using __mmplayer_handle_streaming_error.
3736 __mmplayer_handle_streaming_error(player, msg, error);
3739 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3741 if (error->domain == GST_STREAM_ERROR)
3742 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3743 else if (error->domain == GST_RESOURCE_ERROR)
3744 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3745 else if (error->domain == GST_LIBRARY_ERROR)
3746 ret = __mmplayer_gst_handle_library_error(player, error->code);
3747 else if (error->domain == GST_CORE_ERROR)
3748 ret = __mmplayer_gst_handle_core_error(player, error->code);
3750 g_error_free(error);
3752 player->msg_posted = TRUE;
3754 gst_message_unref(msg);
3756 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3758 gst_object_unref(bus);
3759 g_timer_stop(timer);
3760 g_timer_destroy(timer);
3765 if (MMPLAYER_USE_DECODEBIN(player)) {
3766 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3767 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3768 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3771 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3774 /* generate dot file before returning error */
3775 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3783 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3785 int ret = MM_ERROR_NONE;
3790 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3791 MM_ERROR_PLAYER_NOT_INITIALIZED);
3793 LOGD("current state before doing transition");
3794 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3795 MMPLAYER_PRINT_STATE(player);
3798 LOGD("do async state transition to PLAYING");
3800 /* set pipeline state to PLAYING */
3801 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3803 ret = _mmplayer_gst_set_state(player,
3804 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3805 if (ret != MM_ERROR_NONE) {
3806 LOGE("failed to set state to PLAYING");
3811 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3814 /* generate dot file */
3815 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3822 /* sending event to one of sinkelements */
3824 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3826 GstEvent *event2 = NULL;
3827 GList *sinks = NULL;
3828 gboolean res = FALSE;
3831 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3832 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3834 /* While adding subtitles in live feeds seek is getting called.
3835 Adding defensive check in framework layer.*/
3836 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3837 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3838 LOGE("Should not send seek event during live playback");
3843 if (player->play_subtitle)
3844 event2 = gst_event_copy((const GstEvent *)event);
3846 sinks = player->sink_elements;
3848 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3850 if (GST_IS_ELEMENT(sink)) {
3851 /* keep ref to the event */
3852 gst_event_ref(event);
3854 if ((res = gst_element_send_event(sink, event))) {
3855 LOGD("sending event[%s] to sink element [%s] success!",
3856 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3858 /* rtsp case, async_done is not called after seek during pause state */
3859 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3860 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3861 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3862 LOGD("RTSP seek completed, after pause state..");
3863 player->seek_state = MMPLAYER_SEEK_NONE;
3864 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3870 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3871 sinks = g_list_next(sinks);
3878 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3879 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3882 sinks = g_list_next(sinks);
3885 /* Note : Textbin is not linked to the video or audio bin.
3886 * It needs to send the event to the text sink separately.
3888 if (player->play_subtitle && player->pipeline) {
3889 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3891 if (GST_IS_ELEMENT(text_sink)) {
3892 /* keep ref to the event */
3893 gst_event_ref(event2);
3895 if ((res = gst_element_send_event(text_sink, event2)))
3896 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3897 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3899 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3900 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3902 gst_event_unref(event2);
3906 gst_event_unref(event);
3914 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3915 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3916 gint64 cur, GstSeekType stop_type, gint64 stop)
3918 GstEvent *event = NULL;
3919 gboolean result = FALSE;
3923 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3925 if (player->pipeline && player->pipeline->textbin)
3926 __mmplayer_drop_subtitle(player, FALSE);
3928 event = gst_event_new_seek(rate, format, flags, cur_type,
3929 cur, stop_type, stop);
3931 result = _mmplayer_gst_send_event_to_sink(player, event);
3939 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3941 int ret = MM_ERROR_NONE;
3942 gint64 pos_nsec = 0;
3943 gboolean accurate = FALSE;
3944 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3948 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3950 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3951 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3954 ret = __mmplayer_gst_check_position(player, position);
3955 if (ret != MM_ERROR_NONE) {
3956 LOGW("result of check position info 0x%X", ret);
3957 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3960 if (!__mmplayer_gst_check_seekable(player))
3961 return MM_ERROR_PLAYER_NO_OP;
3963 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3964 position, player->playback_rate, player->duration);
3966 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3967 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3968 This causes problem is position calculation during normal pause resume scenarios also.
3969 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3970 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3971 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3972 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3973 LOGW("getting current position failed in seek");
3975 player->last_position = pos_nsec;
3976 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3979 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3980 LOGD("not completed seek");
3981 return MM_ERROR_PLAYER_DOING_SEEK;
3984 if (!internal_called)
3985 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3987 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3988 that's why set position through property. */
3989 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3990 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3991 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3992 (!player->videodec_linked) && (!player->audiodec_linked)) {
3994 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3995 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3997 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3998 player->seek_state = MMPLAYER_SEEK_NONE;
3999 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4001 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4003 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4005 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4007 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4008 GST_FORMAT_TIME, seek_flags,
4009 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4010 LOGE("failed to set position");
4015 /* NOTE : store last seeking point to overcome some bad operation
4016 * (returning zero when getting current position) of some elements
4018 player->last_position = position;
4020 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4021 if (player->playback_rate > 1.0)
4022 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4024 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4025 LOGD("buffering should be reset after seeking");
4026 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4027 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4031 return MM_ERROR_NONE;
4034 player->pending_seek.is_pending = true;
4035 player->pending_seek.pos = position;
4037 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4038 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4039 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4040 player->pending_seek.pos);
4042 return MM_ERROR_NONE;
4045 player->seek_state = MMPLAYER_SEEK_NONE;
4046 return MM_ERROR_PLAYER_SEEK;
4050 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4052 #define TRICKPLAY_OFFSET GST_MSECOND
4054 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4055 gint64 pos_nsec = 0;
4056 gboolean ret = TRUE;
4058 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4059 MM_ERROR_PLAYER_NOT_INITIALIZED);
4061 current_state = MMPLAYER_CURRENT_STATE(player);
4063 /* NOTE : query position except paused state to overcome some bad operation
4064 * please refer to below comments in details
4066 if (current_state != MM_PLAYER_STATE_PAUSED)
4067 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4069 /* NOTE : get last point to overcome some bad operation of some elements
4070 *(returning zero when getting current position in paused state
4071 * and when failed to get position during seeking
4073 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4074 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4076 if (player->playback_rate < 0.0)
4077 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4079 pos_nsec = player->last_position;
4082 pos_nsec = player->last_position;
4084 player->last_position = pos_nsec;
4086 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4089 if (player->duration > 0 && pos_nsec > player->duration)
4090 pos_nsec = player->duration;
4092 player->last_position = pos_nsec;
4095 *position = pos_nsec;
4097 return MM_ERROR_NONE;
4101 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4103 #define STREAMING_IS_FINISHED 0
4104 #define BUFFERING_MAX_PER 100
4105 #define DEFAULT_PER_VALUE -1
4106 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4108 mmplayer_gst_element_t *mainbin = NULL;
4109 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4110 gint64 buffered_total = 0;
4111 gint64 position = 0;
4112 gint buffered_sec = -1;
4113 GstBufferingMode mode = GST_BUFFERING_STREAM;
4114 gint64 content_size_time = player->duration;
4115 guint64 content_size_bytes = player->http_content_size;
4117 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4119 player->pipeline->mainbin,
4120 MM_ERROR_PLAYER_NOT_INITIALIZED);
4122 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4127 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4128 /* and rtsp is not ready yet. */
4129 LOGW("it's only used for http streaming case");
4130 return MM_ERROR_PLAYER_NO_OP;
4133 if (content_size_time <= 0 || content_size_bytes <= 0) {
4134 LOGW("there is no content size");
4135 return MM_ERROR_NONE;
4138 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4139 LOGW("fail to get current position");
4140 return MM_ERROR_NONE;
4143 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4144 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4146 mainbin = player->pipeline->mainbin;
4147 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4149 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4150 GstQuery *query = NULL;
4151 gint byte_in_rate = 0, byte_out_rate = 0;
4152 gint64 estimated_total = 0;
4154 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4155 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4156 LOGW("fail to get buffering query from queue2");
4158 gst_query_unref(query);
4159 return MM_ERROR_NONE;
4162 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4163 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4165 if (mode == GST_BUFFERING_STREAM) {
4166 /* using only queue in case of push mode(ts / mp3) */
4167 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4168 GST_FORMAT_BYTES, &buffered_total)) {
4169 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4170 end_per = 100 * buffered_total / content_size_bytes;
4173 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4175 guint num_of_ranges = 0;
4176 gint64 start_byte = 0, stop_byte = 0;
4178 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4179 if (estimated_total != STREAMING_IS_FINISHED) {
4180 /* buffered size info from queue2 */
4181 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4182 for (idx = 0; idx < num_of_ranges; idx++) {
4183 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4184 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4186 buffered_total += (stop_byte - start_byte);
4189 end_per = BUFFERING_MAX_PER;
4192 gst_query_unref(query);
4195 if (end_per == DEFAULT_PER_VALUE) {
4196 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4198 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4200 /* buffered size info from multiqueue */
4201 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4202 guint curr_size_bytes = 0;
4203 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4204 "curr-size-bytes", &curr_size_bytes, NULL);
4205 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4206 buffered_total += (gint64)curr_size_bytes;
4209 if (avg_byterate > 0)
4210 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4211 else if (player->total_maximum_bitrate > 0)
4212 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4213 else if (player->total_bitrate > 0)
4214 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4216 if (buffered_sec >= 0)
4217 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4221 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4222 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4224 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4225 buffered_total, buffered_sec, *start_pos, *end_pos);
4227 return MM_ERROR_NONE;
4231 _mmplayer_gst_create_source(mmplayer_t *player)
4233 GstElement *element = NULL;
4236 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4237 player->pipeline->mainbin, NULL);
4239 /* setup source for gapless play */
4240 switch (player->profile.uri_type) {
4242 case MM_PLAYER_URI_TYPE_FILE:
4243 element = __mmplayer_gst_make_file_src(player);
4245 case MM_PLAYER_URI_TYPE_URL_HTTP:
4246 element = __mmplayer_gst_make_http_src(player);
4249 LOGE("not support uri type %d", player->profile.uri_type);
4254 LOGE("failed to create source element");
4263 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4266 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4267 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4269 SECURE_LOGD("uri : %s", player->profile.uri);
4271 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4273 if ((player->v_stream_caps) &&
4274 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4275 return MM_ERROR_PLAYER_INTERNAL;
4277 if ((player->a_stream_caps) &&
4278 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4279 return MM_ERROR_PLAYER_INTERNAL;
4281 if ((player->s_stream_caps) &&
4282 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4283 return MM_ERROR_PLAYER_INTERNAL;
4286 return MM_ERROR_NONE;
4290 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4292 mmplayer_gst_element_t *mainbin = NULL;
4293 GstElement *autoplug_elem = NULL;
4296 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4297 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4299 mainbin = player->pipeline->mainbin;
4301 LOGD("uri type %d", player->profile.uri_type);
4303 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4304 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4305 return MM_ERROR_PLAYER_INTERNAL;
4308 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4309 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4312 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4313 if (!autoplug_elem) {
4314 LOGE("failed to create uridecodebin3 element");
4318 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4319 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4320 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4322 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4323 LOGE("failed to add uridecodebin to pipeline");
4327 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4328 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4329 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4331 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4332 LOGE("failed to create fakesink");
4335 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4337 /* take ownership of fakesink. we are reusing it */
4338 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4340 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4341 LOGE("failed to add fakesink to bin");
4342 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4347 return MM_ERROR_NONE;
4351 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4352 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4354 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4355 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4357 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4358 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4360 return MM_ERROR_PLAYER_INTERNAL;
4364 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4366 mmplayer_gst_element_t *mainbin = NULL;
4367 GstElement *src_elem = NULL;
4368 GstElement *autoplug_elem = NULL;
4369 GList *element_bucket = NULL;
4370 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4373 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4374 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4376 LOGD("uri type %d", player->profile.uri_type);
4378 /* create source element */
4379 switch (player->profile.uri_type) {
4380 case MM_PLAYER_URI_TYPE_URL_RTSP:
4381 src_elem = __mmplayer_gst_make_rtsp_src(player);
4383 case MM_PLAYER_URI_TYPE_URL_HTTP:
4384 src_elem = __mmplayer_gst_make_http_src(player);
4386 case MM_PLAYER_URI_TYPE_FILE:
4387 src_elem = __mmplayer_gst_make_file_src(player);
4389 case MM_PLAYER_URI_TYPE_SS:
4391 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4392 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4394 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4398 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4399 LOGD("get timeout from ini");
4400 http_timeout = player->ini.http_timeout;
4403 /* setting property to streaming source */
4404 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4407 case MM_PLAYER_URI_TYPE_MEM:
4409 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4411 src_elem = gst_element_factory_make("appsrc", "mem-source");
4413 LOGE("failed to create appsrc element");
4417 g_object_set(src_elem, "stream-type", stream_type,
4418 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4420 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4421 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4422 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4423 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4427 LOGE("not support uri type");
4432 LOGE("failed to create source element");
4433 return MM_ERROR_PLAYER_INTERNAL;
4436 mainbin = player->pipeline->mainbin;
4438 /* take source element */
4439 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4441 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4442 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4443 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4445 /* create next element for auto-plugging */
4446 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4447 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4448 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4449 if (!autoplug_elem) {
4450 LOGE("failed to create typefind element");
4454 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4455 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4456 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4457 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4458 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4459 if (!autoplug_elem) {
4460 LOGE("failed to create decodebin");
4464 /* default size of mq in decodebin is 2M
4465 * but it can cause blocking issue during seeking depends on content. */
4466 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4469 if (autoplug_elem) {
4470 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4471 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4472 mainbin[autoplug_elem_id].gst = autoplug_elem;
4474 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4477 /* add elements to pipeline */
4478 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4479 LOGE("failed to add elements to pipeline");
4483 /* linking elements in the bucket by added order. */
4484 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4485 LOGE("failed to link some elements");
4489 /* FIXME: need to check whether this is required or not. */
4490 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4491 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4492 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4493 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4494 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4496 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4497 LOGE("failed to create fakesink");
4500 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4502 /* take ownership of fakesink. we are reusing it */
4503 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4505 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4506 LOGE("failed to add fakesink to bin");
4507 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4512 g_list_free(element_bucket);
4515 return MM_ERROR_NONE;
4518 g_list_free(element_bucket);
4520 if (mainbin[MMPLAYER_M_SRC].gst)
4521 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4523 if (mainbin[autoplug_elem_id].gst)
4524 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4526 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4527 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4529 mainbin[MMPLAYER_M_SRC].gst = NULL;
4530 mainbin[autoplug_elem_id].gst = NULL;
4531 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4533 return MM_ERROR_PLAYER_INTERNAL;
4537 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4540 mmplayer_gst_element_t *mainbin = NULL;
4543 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4544 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4546 mainbin = player->pipeline->mainbin;
4548 /* connect bus callback */
4549 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4551 LOGE("cannot get bus from pipeline");
4552 return MM_ERROR_PLAYER_INTERNAL;
4555 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4556 (GstBusFunc)__mmplayer_gst_msg_push, player,
4557 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4558 if (player->bus_watcher == 0) {
4559 LOGE("failed to add bus watch");
4560 return MM_ERROR_PLAYER_INTERNAL;
4563 g_mutex_init(&player->bus_watcher_mutex);
4564 g_cond_init(&player->bus_watcher_cond);
4566 player->context.thread_default = g_main_context_get_thread_default();
4567 if (player->context.thread_default == NULL) {
4568 player->context.thread_default = g_main_context_default();
4569 LOGD("thread-default context is the global default context");
4571 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4573 /* set sync handler to get tag synchronously */
4574 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4575 gst_object_unref(GST_OBJECT(bus));
4577 /* create gst bus_msb_cb thread */
4578 g_mutex_init(&player->bus_msg_thread_mutex);
4579 g_cond_init(&player->bus_msg_thread_cond);
4580 player->bus_msg_thread_exit = FALSE;
4581 player->bus_msg_thread =
4582 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4583 if (!player->bus_msg_thread) {
4584 LOGE("failed to create gst BUS msg thread");
4585 g_mutex_clear(&player->bus_msg_thread_mutex);
4586 g_cond_clear(&player->bus_msg_thread_cond);
4587 return MM_ERROR_PLAYER_INTERNAL;
4591 return MM_ERROR_NONE;
4595 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4597 int ret = MM_ERROR_NONE;
4598 mmplayer_gst_element_t *mainbin = NULL;
4599 MMMessageParamType msg_param = {0,};
4600 GstElement *element = NULL;
4601 MMHandleType attrs = 0;
4603 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4607 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4608 LOGE("player is not initialized");
4612 mainbin = player->pipeline->mainbin;
4613 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4615 attrs = MMPLAYER_GET_ATTRS(player);
4617 LOGE("fail to get attributes");
4621 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4623 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4624 LOGE("failed to parse profile");
4625 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4629 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4630 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4631 LOGE("dash or hls is not supportable");
4632 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4636 if (!MMPLAYER_USE_DECODEBIN(player)) {
4637 ret = _mmplayer_gst_build_pipeline_with_src(player);
4638 if (ret != MM_ERROR_NONE)
4641 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4642 LOGE("Failed to change state of uridecodebin3 element");
4648 element = _mmplayer_gst_create_source(player);
4650 LOGE("no source element was created");
4654 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4655 LOGE("failed to add source element to pipeline");
4656 gst_object_unref(GST_OBJECT(element));
4661 /* take source element */
4662 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4663 mainbin[MMPLAYER_M_SRC].gst = element;
4667 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4668 if (player->streamer == NULL) {
4669 player->streamer = _mm_player_streaming_create();
4670 _mm_player_streaming_initialize(player->streamer, TRUE);
4673 elem_idx = MMPLAYER_M_TYPEFIND;
4674 element = gst_element_factory_make("typefind", "typefinder");
4675 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4676 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4678 elem_idx = MMPLAYER_M_AUTOPLUG;
4679 element = _mmplayer_gst_make_decodebin(player);
4682 /* check autoplug element is OK */
4684 LOGE("can not create element(%d)", elem_idx);
4688 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4689 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4690 gst_object_unref(GST_OBJECT(element));
4695 mainbin[elem_idx].id = elem_idx;
4696 mainbin[elem_idx].gst = element;
4698 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4699 LOGE("Failed to link src - autoplug(or typefind)");
4703 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4704 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4705 LOGE("Failed to change state of src element");
4709 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4710 LOGE("Failed to change state of decodebin");
4715 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4716 LOGE("Failed to change state of src element");
4721 player->gapless.stream_changed = TRUE;
4722 player->gapless.running = TRUE;
4728 _mmplayer_set_reconfigure_state(player, FALSE);
4729 if (!player->msg_posted) {
4730 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4731 player->msg_posted = TRUE;