4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
58 /* check whether the error is posted from not-activated track or not */
60 gint active_index = 0;
62 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
64 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
65 LOGD("current active pad index -%d", active_index);
67 if (src_element_name) {
70 if (player->audio_decoders) {
71 GList *adec = player->audio_decoders;
72 for (; adec ; adec = g_list_next(adec)) {
73 gchar *name = adec->data;
75 LOGD("found audio decoder name = %s", name);
76 if (g_strrstr(name, src_element_name)) {
83 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
86 if (active_index != msg_src_pos) {
87 LOGD("skip error because error is posted from no activated track");
95 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
97 /* Demuxer can't parse one track because it's corrupted.
98 * So, the decoder for it is not linked.
99 * But, it has one playable track.
101 if (g_strrstr(klass, "Demux")) {
102 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
103 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
104 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
105 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
107 if (player->pipeline->audiobin) { // PCM
108 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
110 LOGD("not found any available codec. Player should be destroyed.");
111 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
116 return MM_ERROR_PLAYER_INVALID_STREAM;
120 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
122 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
123 LOGE("Not supported subtitle.");
124 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
126 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
130 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
132 /* Decoder Custom Message */
133 if (!strstr(error->message, "ongoing"))
134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
136 if (strncasecmp(klass, "audio", 5)) {
137 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
138 LOGD("Video can keep playing.");
139 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
141 } else if (strncasecmp(klass, "video", 5)) {
142 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
143 LOGD("Audio can keep playing.");
144 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
148 LOGD("not found any available codec. Player should be destroyed.");
149 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
153 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
155 if (strstr(error->message, "rights expired"))
156 return MM_ERROR_PLAYER_DRM_EXPIRED;
157 else if (strstr(error->message, "no rights"))
158 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
159 else if (strstr(error->message, "has future rights"))
160 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
161 else if (strstr(error->message, "opl violation"))
162 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
164 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
167 /* NOTE : decide gstreamer state whether there is some playable track or not. */
169 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
171 gchar *src_element_name = NULL;
172 GstElement *src_element = NULL;
173 GstElementFactory *factory = NULL;
174 const gchar *klass = NULL;
178 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
179 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
180 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
181 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
183 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
185 src_element = GST_ELEMENT_CAST(message->src);
186 src_element_name = GST_ELEMENT_NAME(src_element);
187 if (!src_element_name)
188 return MM_ERROR_PLAYER_INTERNAL;
190 factory = gst_element_get_factory(src_element);
192 return MM_ERROR_PLAYER_INTERNAL;
194 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
196 return MM_ERROR_PLAYER_INTERNAL;
198 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
199 error->code, error->message, src_element_name, klass);
201 if (MMPLAYER_USE_DECODEBIN(player) &&
202 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
203 return MM_ERROR_NONE;
205 switch (error->code) {
206 case GST_STREAM_ERROR_DECODE:
207 return __mmplayer_gst_transform_error_decode(player, klass);
208 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
209 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
210 case GST_STREAM_ERROR_WRONG_TYPE:
211 return __mmplayer_gst_transform_error_type(player, src_element);
212 case GST_STREAM_ERROR_FAILED:
213 return __mmplayer_gst_transform_error_failed(player, klass, error);
214 case GST_STREAM_ERROR_DECRYPT:
215 case GST_STREAM_ERROR_DECRYPT_NOKEY:
216 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
217 return __mmplayer_gst_transform_error_decrypt(player, error);
224 return MM_ERROR_PLAYER_INVALID_STREAM;
228 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
230 gint trans_err = MM_ERROR_NONE;
234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 case GST_CORE_ERROR_MISSING_PLUGIN:
238 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
239 case GST_CORE_ERROR_STATE_CHANGE:
240 case GST_CORE_ERROR_SEEK:
241 case GST_CORE_ERROR_NOT_IMPLEMENTED:
242 case GST_CORE_ERROR_FAILED:
243 case GST_CORE_ERROR_TOO_LAZY:
244 case GST_CORE_ERROR_PAD:
245 case GST_CORE_ERROR_THREAD:
246 case GST_CORE_ERROR_NEGOTIATION:
247 case GST_CORE_ERROR_EVENT:
248 case GST_CORE_ERROR_CAPS:
249 case GST_CORE_ERROR_TAG:
250 case GST_CORE_ERROR_CLOCK:
251 case GST_CORE_ERROR_DISABLED:
253 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
263 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
265 gint trans_err = MM_ERROR_NONE;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
272 case GST_LIBRARY_ERROR_FAILED:
273 case GST_LIBRARY_ERROR_TOO_LAZY:
274 case GST_LIBRARY_ERROR_INIT:
275 case GST_LIBRARY_ERROR_SHUTDOWN:
276 case GST_LIBRARY_ERROR_SETTINGS:
277 case GST_LIBRARY_ERROR_ENCODE:
279 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
289 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
291 gint trans_err = MM_ERROR_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
298 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
299 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
301 case GST_RESOURCE_ERROR_NOT_FOUND:
302 case GST_RESOURCE_ERROR_OPEN_READ:
303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
304 || MMPLAYER_IS_RTSP_STREAMING(player)) {
305 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
308 case GST_RESOURCE_ERROR_READ:
309 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
310 || MMPLAYER_IS_RTSP_STREAMING(player)) {
311 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
313 } else if (message != NULL && message->src != NULL) {
314 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
315 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
317 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
318 path_type = MMPLAYER_PATH_VOD;
319 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
320 path_type = MMPLAYER_PATH_TEXT;
322 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
323 /* check storage state */
324 storage_get_state(player->storage_info[path_type].id, &storage_state);
325 player->storage_info[path_type].state = storage_state;
326 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
329 case GST_RESOURCE_ERROR_WRITE:
330 case GST_RESOURCE_ERROR_FAILED:
331 case GST_RESOURCE_ERROR_SEEK:
332 case GST_RESOURCE_ERROR_TOO_LAZY:
333 case GST_RESOURCE_ERROR_BUSY:
334 case GST_RESOURCE_ERROR_OPEN_WRITE:
335 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
336 case GST_RESOURCE_ERROR_CLOSE:
337 case GST_RESOURCE_ERROR_SYNC:
338 case GST_RESOURCE_ERROR_SETTINGS:
340 trans_err = MM_ERROR_PLAYER_INTERNAL;
350 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
352 gint trans_err = MM_ERROR_NONE;
356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
358 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
360 switch (error->code) {
361 case GST_STREAM_ERROR_FAILED:
362 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
363 case GST_STREAM_ERROR_DECODE:
364 case GST_STREAM_ERROR_WRONG_TYPE:
365 case GST_STREAM_ERROR_DECRYPT:
366 case GST_STREAM_ERROR_DECRYPT_NOKEY:
367 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
368 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
371 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
372 case GST_STREAM_ERROR_TOO_LAZY:
373 case GST_STREAM_ERROR_ENCODE:
374 case GST_STREAM_ERROR_DEMUX:
375 case GST_STREAM_ERROR_MUX:
376 case GST_STREAM_ERROR_FORMAT:
378 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
388 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
390 MMMessageParamType msg_param;
391 gchar *msg_src_element;
395 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
396 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
398 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
400 memset(&msg_param, 0, sizeof(MMMessageParamType));
402 if (error->domain == GST_CORE_ERROR) {
403 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
404 } else if (error->domain == GST_LIBRARY_ERROR) {
405 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
406 } else if (error->domain == GST_RESOURCE_ERROR) {
407 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
408 } else if (error->domain == GST_STREAM_ERROR) {
409 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
411 LOGW("This error domain is not defined.");
413 /* we treat system error as an internal error */
414 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
418 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
420 msg_param.data = (void *)error->message;
422 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
423 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
427 if (msg_param.code == MM_ERROR_NONE)
430 /* skip error to avoid duplicated posting */
431 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
432 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
433 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
434 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
436 /* The error will be handled by mused.
437 * @ref _mmplayer_manage_external_storage_state() */
439 LOGW("storage is removed, skip error post");
443 /* post error to application */
444 if (!player->msg_posted) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
446 /* don't post more if one was sent already */
447 player->msg_posted = TRUE;
449 LOGD("skip error post because it's sent already.");
458 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
461 MMMessageParamType msg_param = {0, };
462 gchar *msg_src_element = NULL;
466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
467 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
468 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
470 switch (error->code) {
471 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
472 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
474 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
475 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
477 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
478 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
480 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
481 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
483 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
484 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
486 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
487 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
489 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
490 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
492 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
493 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
495 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
498 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
501 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
504 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
507 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
510 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
513 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
516 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
519 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
522 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
525 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
528 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
531 case MMPLAYER_STREAMING_ERROR_GONE:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
534 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
540 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
543 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
546 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
549 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
552 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
555 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
558 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
561 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
564 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
567 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
570 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
573 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
576 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
579 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
582 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
585 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
588 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
591 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
594 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
597 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
600 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
603 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
608 return MM_ERROR_PLAYER_STREAMING_FAIL;
613 msg_param.data = (void *)(error->message);
616 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
618 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
619 msg_src_element, msg_param.code, (char *)msg_param.data);
622 /* post error to application */
623 if (!player->msg_posted) {
624 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
626 /* don't post more if one was sent already */
627 player->msg_posted = TRUE;
629 LOGD("skip error post because it's sent already.");
638 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
640 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
641 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
642 gst_tag_list_get_string(tags, "stitching_software",
643 &metadata->stitching_software);
644 gst_tag_list_get_string(tags, "projection_type",
645 &metadata->projection_type_string);
646 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
647 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
648 gst_tag_list_get_int(tags, "init_view_heading",
649 &metadata->init_view_heading);
650 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
651 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
652 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
653 gst_tag_list_get_int(tags, "full_pano_width_pixels",
654 &metadata->full_pano_width_pixels);
655 gst_tag_list_get_int(tags, "full_pano_height_pixels",
656 &metadata->full_pano_height_pixels);
657 gst_tag_list_get_int(tags, "cropped_area_image_width",
658 &metadata->cropped_area_image_width);
659 gst_tag_list_get_int(tags, "cropped_area_image_height",
660 &metadata->cropped_area_image_height);
661 gst_tag_list_get_int(tags, "cropped_area_left",
662 &metadata->cropped_area_left);
663 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
664 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
665 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
666 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
670 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
673 /* macro for better code readability */
674 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
676 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
677 if (string != NULL) { \
678 SECURE_LOGD("update tag string : %s", string); \
679 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
680 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
681 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
682 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
683 mm_player_set_attribute((MMHandleType)player, NULL,\
684 playertag, new_string, strlen(new_string), NULL); \
685 MMPLAYER_FREEIF(new_string); \
687 mm_player_set_attribute((MMHandleType)player, NULL,\
688 playertag, string, strlen(string), NULL); \
690 MMPLAYER_FREEIF(string); \
695 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
697 GstSample *sample = NULL;\
698 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
699 GstMapInfo info = GST_MAP_INFO_INIT;\
700 buffer = gst_sample_get_buffer(sample);\
701 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
702 LOGD("failed to get image data from tag");\
703 gst_sample_unref(sample);\
706 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
707 MMPLAYER_FREEIF(player->album_art);\
708 player->album_art = (gchar *)g_malloc(info.size);\
709 if (player->album_art) {\
710 memcpy(player->album_art, info.data, info.size);\
711 mm_player_set_attribute((MMHandleType)player, NULL,\
712 playertag, (void *)player->album_art, info.size, NULL); \
713 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
714 msg_param.data = (void *)player->album_art;\
715 msg_param.size = info.size;\
716 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
717 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
720 gst_buffer_unmap(buffer, &info);\
721 gst_sample_unref(sample);\
725 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
730 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
731 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
732 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
733 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
734 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
736 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
737 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
738 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
739 mm_player_set_attribute((MMHandleType)player, NULL,\
740 "content_audio_bitrate", v_uint, NULL); \
741 player->bitrate[track_type] = v_uint; \
742 player->total_bitrate = 0; \
743 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
744 player->total_bitrate += player->bitrate[i]; \
745 mm_player_set_attribute((MMHandleType)player, NULL,\
746 playertag, player->total_bitrate, NULL); \
747 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
748 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
749 player->maximum_bitrate[track_type] = v_uint; \
750 player->total_maximum_bitrate = 0; \
751 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
752 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, player->total_maximum_bitrate, NULL); \
755 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
757 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
764 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
766 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
768 string = g_strdup_printf("%d", g_date_get_year(date));\
769 mm_player_set_attribute((MMHandleType)player, NULL,\
770 playertag, string, strlen(string), NULL); \
771 SECURE_LOGD("metainfo year : %s", string);\
772 MMPLAYER_FREEIF(string);\
778 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
780 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
781 if (datetime != NULL) {\
782 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, string, strlen(string), NULL); \
785 SECURE_LOGD("metainfo year : %s", string);\
786 MMPLAYER_FREEIF(string);\
787 gst_date_time_unref(datetime);\
793 GstTagList *tag_list = NULL;
798 GstDateTime *datetime = NULL;
800 GstBuffer *buffer = NULL;
802 MMMessageParamType msg_param = {0, };
804 /* currently not used. but those are needed for above macro */
805 //guint64 v_uint64 = 0;
806 //gdouble v_double = 0;
808 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
810 /* get tag list from gst message */
811 gst_message_parse_tag(msg, &tag_list);
813 /* store tags to player attributes */
814 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
815 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
816 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
817 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
818 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
819 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
821 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
823 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
827 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
828 MMPLAYER_UPDATE_TAG_LOCK(player);
829 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
830 MMPLAYER_UPDATE_TAG_UNLOCK(player);
831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
833 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
834 if (player->video360_metadata.is_spherical == -1) {
835 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
836 mm_player_set_attribute((MMHandleType)player, NULL,
837 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
838 if (player->video360_metadata.is_spherical == 1) {
839 LOGD("This is spherical content for 360 playback.");
840 player->is_content_spherical = TRUE;
842 LOGD("This is not spherical content");
843 player->is_content_spherical = FALSE;
846 if (player->video360_metadata.projection_type_string) {
847 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
848 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
850 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
851 player->is_content_spherical = player->is_video360_enabled = FALSE;
855 if (player->video360_metadata.stereo_mode_string) {
856 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
857 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
858 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
859 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
860 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
861 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
863 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
864 player->is_content_spherical = player->is_video360_enabled = FALSE;
870 gst_tag_list_unref(tag_list);
876 static mmplayer_track_type_e
877 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
880 case GST_STREAM_TYPE_AUDIO:
881 return MM_PLAYER_TRACK_TYPE_AUDIO;
882 case GST_STREAM_TYPE_VIDEO:
883 return MM_PLAYER_TRACK_TYPE_VIDEO;
884 case GST_STREAM_TYPE_TEXT:
885 return MM_PLAYER_TRACK_TYPE_TEXT;
887 LOGD("not supported stream stype");
888 return MM_PLAYER_TRACK_TYPE_MAX;
892 /* if retval is FALSE, it will be dropped for performance. */
894 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
896 gboolean retval = FALSE;
898 if (!(player->pipeline && player->pipeline->mainbin)) {
899 LOGE("player pipeline handle is null");
903 switch (GST_MESSAGE_TYPE(message)) {
904 case GST_MESSAGE_TAG:
905 case GST_MESSAGE_EOS:
906 case GST_MESSAGE_ERROR:
907 case GST_MESSAGE_WARNING:
908 case GST_MESSAGE_CLOCK_LOST:
909 case GST_MESSAGE_NEW_CLOCK:
910 case GST_MESSAGE_ELEMENT:
911 case GST_MESSAGE_DURATION_CHANGED:
912 case GST_MESSAGE_ASYNC_START:
913 case GST_MESSAGE_STREAM_COLLECTION:
916 case GST_MESSAGE_ASYNC_DONE:
917 case GST_MESSAGE_STATE_CHANGED:
918 /* we only handle messages from pipeline */
919 MMPLAYER_RECONFIGURE_LOCK(player);
920 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
924 MMPLAYER_RECONFIGURE_UNLOCK(player);
926 case GST_MESSAGE_BUFFERING:
928 gint buffer_percent = 0;
931 gst_message_parse_buffering(message, &buffer_percent);
932 if (buffer_percent != MAX_BUFFER_PERCENT) {
933 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
937 if (!MMPLAYER_CMD_TRYLOCK(player)) {
938 LOGW("can't get cmd lock, send msg to bus");
942 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
943 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
944 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
947 MMPLAYER_CMD_UNLOCK(player);
951 case GST_MESSAGE_STREAMS_SELECTED:
953 if (MMPLAYER_USE_DECODEBIN(player))
954 break; /* drop msg */
956 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
957 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
958 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
960 gint64 dur_bytes = 0L;
962 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
963 LOGE("fail to get duration.");
965 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
966 * use file information was already set on Q2 when it was created. */
967 _mm_player_streaming_set_queue2(player->streamer,
968 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
969 TRUE, /* use_buffering */
970 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
971 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
974 LOGD("GST_MESSAGE_STREAMS_SELECTED");
975 player->no_more_pad = TRUE;
976 _mmplayer_set_reconfigure_state(player, FALSE);
977 if (!MMPLAYER_IS_ADAPTIVE_STREAMING(player))
978 _mmplayer_pipeline_complete(NULL, player);
991 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
993 guint64 data_size = 0;
996 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
998 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1000 if (MMPLAYER_IS_HTTP_STREAMING(player))
1001 data_size = player->http_content_size;
1003 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1004 if (!player->streamer->is_adaptive_streaming) {
1005 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1009 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1010 if (!player->streamer->buffering_req.is_pre_buffering) {
1011 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1012 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1013 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1019 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1021 int ret = MM_ERROR_NONE;
1022 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1023 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1024 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1025 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1027 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1028 LOGW("do nothing for buffering msg");
1029 ret = MM_ERROR_PLAYER_INVALID_STATE;
1033 prev_state = MMPLAYER_PREV_STATE(player);
1034 current_state = MMPLAYER_CURRENT_STATE(player);
1035 target_state = MMPLAYER_TARGET_STATE(player);
1036 pending_state = MMPLAYER_PENDING_STATE(player);
1038 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1039 MMPLAYER_STATE_GET_NAME(prev_state),
1040 MMPLAYER_STATE_GET_NAME(current_state),
1041 MMPLAYER_STATE_GET_NAME(pending_state),
1042 MMPLAYER_STATE_GET_NAME(target_state),
1043 player->streamer->buffering_state);
1045 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1046 /* NOTE : if buffering has done, player has to go to target state. */
1047 switch (target_state) {
1048 case MM_PLAYER_STATE_PAUSED:
1050 switch (pending_state) {
1051 case MM_PLAYER_STATE_PLAYING:
1052 _mmplayer_gst_pause(player, TRUE);
1055 case MM_PLAYER_STATE_PAUSED:
1056 LOGD("player is already going to paused state, there is nothing to do.");
1059 case MM_PLAYER_STATE_NONE:
1060 case MM_PLAYER_STATE_NULL:
1061 case MM_PLAYER_STATE_READY:
1063 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1069 case MM_PLAYER_STATE_PLAYING:
1071 switch (pending_state) {
1072 case MM_PLAYER_STATE_NONE:
1074 if (current_state != MM_PLAYER_STATE_PLAYING)
1075 _mmplayer_gst_resume(player, TRUE);
1079 case MM_PLAYER_STATE_PAUSED:
1080 /* NOTE: It should be worked as asynchronously.
1081 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1083 if (current_state == MM_PLAYER_STATE_PLAYING) {
1084 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1085 * The current state should be changed to paused purposely to prevent state conflict.
1087 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1089 _mmplayer_gst_resume(player, TRUE);
1092 case MM_PLAYER_STATE_PLAYING:
1093 LOGD("player is already going to playing state, there is nothing to do.");
1096 case MM_PLAYER_STATE_NULL:
1097 case MM_PLAYER_STATE_READY:
1099 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1105 case MM_PLAYER_STATE_NULL:
1106 case MM_PLAYER_STATE_READY:
1107 case MM_PLAYER_STATE_NONE:
1109 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1113 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1114 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1116 switch (pending_state) {
1117 case MM_PLAYER_STATE_NONE:
1119 if (current_state != MM_PLAYER_STATE_PAUSED) {
1120 /* rtsp streaming pause makes rtsp server stop sending data. */
1121 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1122 LOGD("set pause state during buffering");
1123 _mmplayer_gst_pause(player, TRUE);
1129 case MM_PLAYER_STATE_PLAYING:
1130 /* rtsp streaming pause makes rtsp server stop sending data. */
1131 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1132 _mmplayer_gst_pause(player, TRUE);
1135 case MM_PLAYER_STATE_PAUSED:
1138 case MM_PLAYER_STATE_NULL:
1139 case MM_PLAYER_STATE_READY:
1141 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1150 static stream_variant_t *
1151 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1153 stream_variant_t *var_info = NULL;
1154 g_return_val_if_fail(self != NULL, NULL);
1156 var_info = g_new0(stream_variant_t, 1);
1157 if (!var_info) return NULL;
1158 var_info->bandwidth = self->bandwidth;
1159 var_info->width = self->width;
1160 var_info->height = self->height;
1165 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1171 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1172 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1174 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1175 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1176 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1178 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1179 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1180 player->http_content_size = (bytes > 0) ? bytes : 0;
1183 /* handling audio clip which has vbr. means duration is keep changing */
1184 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1193 __mmplayer_eos_timer_cb(gpointer u_data)
1195 mmplayer_t *player = NULL;
1196 MMHandleType attrs = 0;
1199 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1201 player = (mmplayer_t *)u_data;
1202 attrs = MMPLAYER_GET_ATTRS(player);
1204 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1208 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1209 if (ret_value != MM_ERROR_NONE)
1210 LOGE("seeking to 0 failed in repeat play");
1213 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1216 /* we are returning FALSE as we need only one posting */
1221 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1223 MMPLAYER_RETURN_IF_FAIL(player);
1225 /* post now if delay is zero */
1226 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1227 LOGD("eos delay is zero. posting EOS now");
1228 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1230 if (player->audio_decoded_cb)
1231 _mmplayer_cancel_eos_timer(player);
1236 /* cancel if existing */
1237 _mmplayer_cancel_eos_timer(player);
1239 /* init new timeout */
1240 /* NOTE : consider give high priority to this timer */
1241 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1243 player->eos_timer = g_timeout_add(delay_in_ms,
1244 __mmplayer_eos_timer_cb, player);
1246 player->context.global_default = g_main_context_default();
1247 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1249 /* check timer is valid. if not, send EOS now */
1250 if (player->eos_timer == 0) {
1251 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1252 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1257 __mmplayer_gst_pending_seek(mmplayer_t *player)
1259 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1260 int ret = MM_ERROR_NONE;
1264 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1266 if (!player->pending_seek.is_pending) {
1267 LOGD("pending seek is not reserved. nothing to do.");
1271 /* check player state if player could pending seek or not. */
1272 current_state = MMPLAYER_CURRENT_STATE(player);
1274 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1275 LOGW("try to pending seek in %s state, try next time. ",
1276 MMPLAYER_STATE_GET_NAME(current_state));
1280 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1282 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1283 if (ret != MM_ERROR_NONE)
1284 LOGE("failed to seek pending position. just keep staying current position.");
1286 player->pending_seek.is_pending = false;
1294 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1296 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1298 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1300 audiobin = player->pipeline->audiobin; /* can be null */
1301 videobin = player->pipeline->videobin; /* can be null */
1302 textbin = player->pipeline->textbin; /* can be null */
1304 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1306 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1307 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1309 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1310 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1312 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1313 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1319 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1321 mmplayer_gst_element_t *textbin;
1324 MMPLAYER_RETURN_IF_FAIL(player &&
1326 player->pipeline->textbin);
1328 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1330 textbin = player->pipeline->textbin;
1333 LOGD("Drop subtitle text after getting EOS");
1335 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1336 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1338 player->is_subtitle_force_drop = TRUE;
1340 if (player->is_subtitle_force_drop == TRUE) {
1341 LOGD("Enable subtitle data path without drop");
1343 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1344 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1346 LOGD("non-connected with external display");
1348 player->is_subtitle_force_drop = FALSE;
1354 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1356 MMHandleType attrs = 0;
1361 /* NOTE : EOS event is coming multiple time. watch out it */
1362 /* check state. we only process EOS when pipeline state goes to PLAYING */
1363 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1364 LOGD("EOS received on non-playing state. ignoring it");
1368 if (player->pipeline && player->pipeline->textbin)
1369 __mmplayer_drop_subtitle(player, TRUE);
1371 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1372 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1374 /* rewind if repeat count is greater then zero */
1375 /* get play count */
1376 attrs = MMPLAYER_GET_ATTRS(player);
1378 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1380 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1382 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1383 if (player->playback_rate < 0.0) {
1384 player->resumed_by_rewind = TRUE;
1385 _mmplayer_set_mute((MMHandleType)player, false);
1386 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1389 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1392 player->sent_bos = FALSE;
1394 LOGD("do not post eos msg for repeating");
1399 if (player->pipeline)
1400 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1402 /* post eos message to application */
1403 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1405 /* reset last position */
1406 player->last_position = 0;
1413 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1415 GError *error = NULL;
1416 gchar *debug = NULL;
1420 /* generating debug info before returning error */
1421 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1423 /* get error code */
1424 gst_message_parse_error(msg, &error, &debug);
1426 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1427 /* Note : the streaming error from the streaming source is handled
1428 * using __mmplayer_handle_streaming_error.
1430 __mmplayer_handle_streaming_error(player, msg, error);
1432 /* dump state of all element */
1433 _mmplayer_dump_pipeline_state(player);
1435 /* translate gst error code to msl error code. then post it
1436 * to application if needed
1438 __mmplayer_handle_gst_error(player, msg, error);
1441 LOGE("error debug : %s", debug);
1444 MMPLAYER_FREEIF(debug);
1445 g_error_free(error);
1452 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1454 MMMessageParamType msg_param = {0, };
1455 int bRet = MM_ERROR_NONE;
1458 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1460 if (!MMPLAYER_IS_STREAMING(player)) {
1461 LOGW("this is not streaming playback.");
1465 MMPLAYER_CMD_LOCK(player);
1467 if (!player->streamer) {
1468 LOGW("Pipeline is shutting down");
1469 MMPLAYER_CMD_UNLOCK(player);
1473 /* ignore the remained buffering message till getting 100% msg */
1474 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1475 gint buffer_percent = 0;
1477 gst_message_parse_buffering(msg, &buffer_percent);
1479 if (buffer_percent == MAX_BUFFER_PERCENT) {
1480 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1481 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1482 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1484 MMPLAYER_CMD_UNLOCK(player);
1488 /* ignore the remained buffering message */
1489 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1490 gint buffer_percent = 0;
1492 gst_message_parse_buffering(msg, &buffer_percent);
1494 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1495 player->streamer->buffering_percent, buffer_percent);
1497 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1498 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1499 player->streamer->buffering_req.is_pre_buffering = FALSE;
1501 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1503 LOGD("interrupted buffering - ignored the remained buffering msg!");
1504 MMPLAYER_CMD_UNLOCK(player);
1509 __mmplayer_update_buffer_setting(player, msg);
1511 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1513 if (bRet == MM_ERROR_NONE) {
1514 msg_param.connection.buffering = player->streamer->buffering_percent;
1515 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1517 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1518 player->pending_resume &&
1519 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1521 player->is_external_subtitle_added_now = FALSE;
1522 player->pending_resume = FALSE;
1523 _mmplayer_resume((MMHandleType)player);
1526 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1527 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1530 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1531 player->seek_state = MMPLAYER_SEEK_NONE;
1532 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1533 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1534 /* Considering the async state transition in case of RTSP.
1535 After getting state change gst msg, seek completed msg will be posted. */
1536 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1540 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1541 if (!player->streamer) {
1542 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1543 MMPLAYER_CMD_UNLOCK(player);
1547 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1549 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1550 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1552 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1553 msg_param.connection.buffering = player->streamer->buffering_percent;
1554 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1556 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1559 msg_param.connection.buffering = player->streamer->buffering_percent;
1560 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1563 MMPLAYER_CMD_UNLOCK(player);
1571 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1573 mmplayer_gst_element_t *mainbin;
1574 GstState oldstate = GST_STATE_NULL;
1575 GstState newstate = GST_STATE_NULL;
1576 GstState pending = GST_STATE_NULL;
1579 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1581 mainbin = player->pipeline->mainbin;
1583 /* we only handle messages from pipeline */
1584 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1587 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pending);
1589 LOGD("state changed [%s] : %s ---> %s final : %s",
1590 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1591 gst_element_state_get_name((GstState)oldstate),
1592 gst_element_state_get_name((GstState)newstate),
1593 gst_element_state_get_name((GstState)pending));
1595 if (newstate == GST_STATE_PLAYING) {
1596 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1598 int retVal = MM_ERROR_NONE;
1599 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1601 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1603 if (MM_ERROR_NONE != retVal)
1604 LOGE("failed to seek pending position. just keep staying current position.");
1606 player->pending_seek.is_pending = false;
1610 if (oldstate == newstate) {
1611 LOGD("pipeline reports state transition to old state");
1616 case GST_STATE_PAUSED:
1618 gboolean prepare_async = FALSE;
1620 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1621 // managed prepare async case
1622 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1623 LOGD("checking prepare mode for async transition - %d", prepare_async);
1626 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1627 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1629 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1630 _mm_player_streaming_set_content_bitrate(player->streamer,
1631 player->total_maximum_bitrate, player->total_bitrate);
1633 if (player->pending_seek.is_pending) {
1634 LOGW("trying to do pending seek");
1635 MMPLAYER_CMD_LOCK(player);
1636 __mmplayer_gst_pending_seek(player);
1637 MMPLAYER_CMD_UNLOCK(player);
1643 case GST_STATE_PLAYING:
1645 if (MMPLAYER_IS_STREAMING(player)) {
1646 // managed prepare async case when buffering is completed
1647 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1648 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1649 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1650 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1652 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1654 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1655 if (player->streamer->buffering_percent < 100) {
1657 MMMessageParamType msg_param = {0, };
1658 LOGW("Posting Buffering Completed Message to Application !!!");
1660 msg_param.connection.buffering = 100;
1661 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1666 if (player->gapless.stream_changed) {
1667 _mmplayer_update_content_attrs(player, ATTR_ALL);
1668 player->gapless.stream_changed = FALSE;
1671 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1672 player->seek_state = MMPLAYER_SEEK_NONE;
1673 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1677 case GST_STATE_VOID_PENDING:
1678 case GST_STATE_NULL:
1679 case GST_STATE_READY:
1689 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1691 const gchar *structure_name;
1692 gint count = 0, idx = 0;
1695 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1697 if (gst_message_get_structure(msg) == NULL)
1700 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1701 if (!structure_name)
1704 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1706 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1707 const GValue *var_info = NULL;
1709 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1710 if (var_info != NULL) {
1711 if (player->adaptive_info.var_list)
1712 g_list_free_full(player->adaptive_info.var_list, g_free);
1714 /* share addr or copy the list */
1715 player->adaptive_info.var_list =
1716 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1718 count = g_list_length(player->adaptive_info.var_list);
1720 stream_variant_t *temp = NULL;
1722 /* print out for debug */
1723 LOGD("num of variant_info %d", count);
1724 for (idx = 0; idx < count; idx++) {
1725 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1727 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1733 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1734 gint num_buffers = 0;
1735 gint extra_num_buffers = 0;
1737 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1738 LOGD("video_num_buffers : %d", num_buffers);
1739 mm_player_set_attribute((MMHandleType)player, NULL,
1740 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1743 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1744 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1745 mm_player_set_attribute((MMHandleType)player, NULL,
1746 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1751 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1752 _mmplayer_track_update_text_attr_info(player, msg);
1754 /* custom message */
1755 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1756 MMMessageParamType msg_param = {0,};
1757 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1758 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1761 /* custom message for RTSP attribute :
1762 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1763 sdp which has contents info is received when rtsp connection is opened.
1764 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1765 if (!strcmp(structure_name, "rtspsrc_properties")) {
1766 g_autofree gchar *audio_codec = NULL;
1767 g_autofree gchar *video_codec = NULL;
1768 g_autofree gchar *video_frame_size = NULL;
1770 gst_structure_get(gst_message_get_structure(msg),
1771 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1772 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1773 player->streaming_type = _mmplayer_get_stream_service_type(player);
1775 gst_structure_get(gst_message_get_structure(msg),
1776 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1777 LOGD("rtsp_audio_codec : %s", audio_codec);
1779 mm_player_set_attribute((MMHandleType)player, NULL,
1780 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1782 gst_structure_get(gst_message_get_structure(msg),
1783 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1784 LOGD("rtsp_video_codec : %s", video_codec);
1786 mm_player_set_attribute((MMHandleType)player, NULL,
1787 "content_video_codec", video_codec, strlen(video_codec), NULL);
1789 gst_structure_get(gst_message_get_structure(msg),
1790 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1791 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1792 if (video_frame_size) {
1793 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1794 mm_player_set_attribute((MMHandleType)player, NULL,
1795 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1796 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1798 g_strfreev(res_str);
1807 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1809 mmplayer_gst_element_t *mainbin;
1812 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1814 mainbin = player->pipeline->mainbin;
1816 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1818 /* we only handle messages from pipeline */
1819 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1822 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1823 if (player->is_external_subtitle_present)
1824 _mmplayer_sync_subtitle_pipeline(player);
1826 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1827 player->seek_state = MMPLAYER_SEEK_NONE;
1828 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1829 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1830 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1831 LOGD("sync %s state(%s) with parent state(%s)",
1832 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1833 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1834 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1836 /* In case of streaming, pause is required before finishing seeking by buffering.
1837 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1838 Because the buffering state is controlled according to the state transition for force resume,
1839 the decodebin state should be paused as player state. */
1840 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1843 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1844 (player->streamer) &&
1845 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1846 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1847 GstQuery *query = NULL;
1848 gboolean busy = FALSE;
1851 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1852 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1853 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1854 gst_query_parse_buffering_percent(query, &busy, &percent);
1855 gst_query_unref(query);
1857 LOGD("buffered percent(%s): %d",
1858 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1862 __mmplayer_handle_buffering_playback(player);
1865 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1875 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1877 GValue val = { 0, };
1879 guint indent = GPOINTER_TO_UINT(user_data);
1881 if (!gst_tag_list_copy_value(&val, tags, tag))
1884 if (G_VALUE_HOLDS_STRING(&val))
1885 str = g_value_dup_string(&val);
1887 str = gst_value_serialize(&val);
1889 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1891 g_value_unset(&val);
1896 __mmplayer_dump_collection(GstStreamCollection * collection)
1900 GstTagList *tags = NULL;
1902 GstCaps *caps = NULL;
1904 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1905 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1906 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1907 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1908 gst_stream_get_stream_flags(stream));
1909 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1911 caps = gst_stream_get_caps(stream);
1913 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1914 gst_caps_unref(caps);
1918 tags = gst_stream_get_tags(stream);
1921 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1922 gst_tag_list_unref(tags);
1929 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1930 GstStream *stream, GParamSpec *pspec, gpointer data)
1932 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1933 gst_stream_get_stream_id(stream), pspec->name, collection);
1934 if (g_str_equal(pspec->name, "caps")) {
1935 GstCaps *caps = gst_stream_get_caps(stream);
1936 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1937 gst_caps_unref(caps);
1941 if (g_str_equal (pspec->name, "tags")) {
1942 GstTagList *tags = gst_stream_get_tags(stream);
1945 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1946 gst_tag_list_unref(tags);
1953 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1955 mmplayer_t *player = (mmplayer_t *)(data);
1957 MMPLAYER_RETURN_IF_FAIL(player);
1958 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1960 switch (GST_MESSAGE_TYPE(msg)) {
1961 case GST_MESSAGE_UNKNOWN:
1962 LOGD("unknown message received");
1965 case GST_MESSAGE_EOS:
1966 LOGD("GST_MESSAGE_EOS received");
1967 __mmplayer_gst_handle_eos_message(player, msg);
1970 case GST_MESSAGE_ERROR:
1971 _mmplayer_set_reconfigure_state(player, FALSE);
1972 __mmplayer_gst_handle_error_message(player, msg);
1975 case GST_MESSAGE_WARNING:
1978 GError *error = NULL;
1980 gst_message_parse_warning(msg, &error, &debug);
1982 LOGD("warning : %s", error->message);
1983 LOGD("debug : %s", debug);
1985 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1987 MMPLAYER_FREEIF(debug);
1988 g_error_free(error);
1992 case GST_MESSAGE_TAG:
1994 LOGD("GST_MESSAGE_TAG");
1995 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1996 LOGW("failed to extract tags from gstmessage");
2000 case GST_MESSAGE_BUFFERING:
2001 __mmplayer_gst_handle_buffering_message(player, msg);
2004 case GST_MESSAGE_STATE_CHANGED:
2005 __mmplayer_gst_handle_state_message(player, msg);
2008 case GST_MESSAGE_CLOCK_LOST:
2010 GstClock *clock = NULL;
2011 gboolean need_new_clock = FALSE;
2013 gst_message_parse_clock_lost(msg, &clock);
2014 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2016 if (!player->videodec_linked)
2017 need_new_clock = TRUE;
2018 else if (!player->ini.use_system_clock)
2019 need_new_clock = TRUE;
2021 if (need_new_clock) {
2022 LOGD("Provide clock is TRUE, do pause->resume");
2023 _mmplayer_gst_pause(player, FALSE);
2024 _mmplayer_gst_resume(player, FALSE);
2029 case GST_MESSAGE_NEW_CLOCK:
2031 GstClock *clock = NULL;
2032 gst_message_parse_new_clock(msg, &clock);
2033 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2037 case GST_MESSAGE_ELEMENT:
2038 __mmplayer_gst_handle_element_message(player, msg);
2041 case GST_MESSAGE_DURATION_CHANGED:
2043 LOGD("GST_MESSAGE_DURATION_CHANGED");
2044 if (!__mmplayer_gst_handle_duration(player, msg))
2045 LOGW("failed to update duration");
2049 case GST_MESSAGE_ASYNC_START:
2050 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2053 case GST_MESSAGE_ASYNC_DONE:
2054 __mmplayer_gst_handle_async_done_message(player, msg);
2056 case GST_MESSAGE_STREAM_COLLECTION:
2058 GstStreamCollection *collection = NULL;
2059 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2061 gst_message_parse_stream_collection(msg, &collection);
2063 __mmplayer_dump_collection(collection);
2064 if (player->collection && player->stream_notify_id) {
2065 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2066 player->stream_notify_id = 0;
2068 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2069 if (player->collection) {
2070 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2071 (GCallback)__mmplayer_stream_notify_cb, player);
2073 gst_object_unref(collection);
2076 case GST_MESSAGE_STREAMS_SELECTED:
2078 GstStreamCollection *collection = NULL;
2079 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2081 gst_message_parse_streams_selected(msg, &collection);
2083 guint len = gst_message_streams_selected_get_size(msg);
2084 for (guint i = 0; i < len; i++) {
2085 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2086 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2087 gst_stream_get_stream_type(stream));
2088 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2089 LOGD("not supported track type");
2090 gst_object_unref(stream);
2093 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2094 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2095 int stream_index = INVALID_TRACK_INDEX;
2096 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2097 player->track[type].active_track_index = stream_index;
2098 LOGD("selected this stream, update active idx : %d",
2099 player->track[type].active_track_index);
2102 gst_object_unref(stream);
2104 gst_object_unref(collection);
2109 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2110 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2111 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2112 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2113 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2114 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2115 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2116 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2117 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2118 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2119 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2120 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2121 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2122 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2123 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2130 /* should not call 'gst_message_unref(msg)' */
2134 static GstBusSyncReply
2135 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2137 mmplayer_t *player = (mmplayer_t *)data;
2138 GstBusSyncReply reply = GST_BUS_DROP;
2140 if (!(player->pipeline && player->pipeline->mainbin)) {
2141 LOGE("player pipeline handle is null");
2142 return GST_BUS_PASS;
2145 if (!__mmplayer_gst_check_useful_message(player, message)) {
2146 gst_message_unref(message);
2147 return GST_BUS_DROP;
2150 switch (GST_MESSAGE_TYPE(message)) {
2151 case GST_MESSAGE_TAG:
2152 __mmplayer_gst_extract_tag_from_msg(player, message);
2156 GstTagList *tags = NULL;
2158 gst_message_parse_tag(message, &tags);
2160 LOGE("TAGS received from element \"%s\".",
2161 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2163 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2164 gst_tag_list_unref(tags);
2172 case GST_MESSAGE_DURATION_CHANGED:
2173 __mmplayer_gst_handle_duration(player, message);
2175 case GST_MESSAGE_ELEMENT:
2177 const gchar *klass = NULL;
2178 klass = gst_element_factory_get_metadata
2179 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2180 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2181 reply = GST_BUS_PASS;
2184 __mmplayer_gst_handle_element_message(player, message);
2187 case GST_MESSAGE_ASYNC_DONE:
2188 /* NOTE:Don't call gst_callback directly
2189 * because previous frame can be showed even though this message is received for seek.
2192 reply = GST_BUS_PASS;
2196 if (reply == GST_BUS_DROP)
2197 gst_message_unref(message);
2203 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2205 GstElement *appsrc = element;
2206 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2207 GstBuffer *buffer = NULL;
2208 GstFlowReturn ret = GST_FLOW_OK;
2211 MMPLAYER_RETURN_IF_FAIL(element);
2212 MMPLAYER_RETURN_IF_FAIL(buf);
2214 buffer = gst_buffer_new();
2216 if (buf->offset < 0 || buf->len < 0) {
2217 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2221 if (buf->offset >= buf->len) {
2222 LOGD("call eos appsrc");
2223 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2227 if (buf->len - buf->offset < size)
2228 len = buf->len - buf->offset;
2230 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2231 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2232 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2235 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2237 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2243 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2245 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2247 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2249 buf->offset = (int)size;
2255 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2257 mmplayer_t *player = (mmplayer_t *)user_data;
2258 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2259 MMMessageParamType msg_param = {0,};
2260 guint64 current_level_bytes = 0;
2262 MMPLAYER_RETURN_IF_FAIL(player);
2264 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2265 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2266 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2267 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2269 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2273 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2275 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2277 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2278 msg_param.buffer_status.stream_type = stream_type;
2279 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2280 msg_param.buffer_status.bytes = current_level_bytes;
2282 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2286 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2288 mmplayer_t *player = (mmplayer_t *)user_data;
2289 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2290 MMMessageParamType msg_param = {0,};
2291 guint64 current_level_bytes = 0;
2293 MMPLAYER_RETURN_IF_FAIL(player);
2295 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2296 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2297 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2298 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2300 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2304 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2306 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2308 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2309 msg_param.buffer_status.stream_type = stream_type;
2310 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2311 msg_param.buffer_status.bytes = current_level_bytes;
2313 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2317 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2319 mmplayer_t *player = (mmplayer_t *)user_data;
2320 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2321 MMMessageParamType msg_param = {0,};
2323 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2325 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2326 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2327 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2328 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2330 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2334 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2336 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2337 msg_param.seek_data.stream_type = stream_type;
2338 msg_param.seek_data.offset = position;
2340 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2346 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2348 #define MAX_LEN_NAME 20
2350 gboolean ret = FALSE;
2351 GstPad *sinkpad = NULL;
2352 gchar *prefix = NULL;
2353 gchar dec_name[MAX_LEN_NAME] = {0, };
2354 main_element_id_e elem_id = MMPLAYER_M_NUM;
2356 mmplayer_gst_element_t *mainbin = NULL;
2357 GstElement *decodebin = NULL;
2358 GstCaps *dec_caps = NULL;
2362 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2364 player->pipeline->mainbin, FALSE);
2365 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2367 mainbin = player->pipeline->mainbin;
2369 case MM_PLAYER_STREAM_TYPE_AUDIO:
2371 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2373 case MM_PLAYER_STREAM_TYPE_VIDEO:
2375 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2378 LOGE("invalid type %d", type);
2382 if (mainbin[elem_id].gst) {
2383 LOGE("elem(%d) is already created", elem_id);
2387 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2389 /* create decodebin */
2390 decodebin = gst_element_factory_make("decodebin", dec_name);
2392 LOGE("failed to create %s", dec_name);
2396 /* raw pad handling signal */
2397 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2398 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2400 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2401 before looking for any elements that can handle that stream.*/
2402 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2403 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2405 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2406 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2407 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2409 /* This signal is emitted when a element is added to the bin.*/
2410 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2411 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2413 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2414 LOGE("failed to add new decodebin");
2418 dec_caps = gst_pad_query_caps(srcpad, NULL);
2421 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2423 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2424 gst_caps_unref(dec_caps);
2427 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2429 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2430 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2433 gst_object_unref(GST_OBJECT(sinkpad));
2435 gst_element_sync_state_with_parent(decodebin);
2437 mainbin[elem_id].id = elem_id;
2438 mainbin[elem_id].gst = decodebin;
2445 gst_object_unref(GST_OBJECT(sinkpad));
2448 gst_element_set_state(decodebin, GST_STATE_NULL);
2449 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2450 gst_object_unref(decodebin);
2458 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2460 #define MAX_LEN_NAME 20
2461 mmplayer_gst_element_t *mainbin = NULL;
2462 gchar *prefix = NULL;
2463 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2465 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2466 GstElement *src = NULL, *queue = NULL;
2467 GstPad *srcpad = NULL;
2470 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2471 player->pipeline->mainbin, FALSE);
2473 mainbin = player->pipeline->mainbin;
2475 LOGD("type(%d) path is creating", type);
2477 case MM_PLAYER_STREAM_TYPE_AUDIO:
2479 if (mainbin[MMPLAYER_M_SRC].gst)
2480 src_id = MMPLAYER_M_2ND_SRC;
2482 src_id = MMPLAYER_M_SRC;
2483 queue_id = MMPLAYER_M_A_BUFFER;
2485 case MM_PLAYER_STREAM_TYPE_VIDEO:
2487 src_id = MMPLAYER_M_SRC;
2488 queue_id = MMPLAYER_M_V_BUFFER;
2490 case MM_PLAYER_STREAM_TYPE_TEXT:
2491 prefix = "subtitle";
2492 src_id = MMPLAYER_M_SUBSRC;
2493 queue_id = MMPLAYER_M_S_BUFFER;
2496 LOGE("invalid type %d", type);
2500 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2501 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2504 src = gst_element_factory_make("appsrc", src_name);
2506 LOGF("failed to create %s", src_name);
2510 mainbin[src_id].id = src_id;
2511 mainbin[src_id].gst = src;
2513 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2514 "caps", caps, NULL);
2516 /* size of many video frames are larger than default blocksize as 4096 */
2517 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2518 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2520 if (player->media_stream_buffer_max_size[type] > 0)
2521 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2523 if (player->media_stream_buffer_min_percent[type] > 0)
2524 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2526 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2527 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2529 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2530 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2531 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2532 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2533 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2534 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2537 queue = gst_element_factory_make("queue2", queue_name);
2539 LOGE("failed to create %s", queue_name);
2542 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2544 mainbin[queue_id].id = queue_id;
2545 mainbin[queue_id].gst = queue;
2547 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2548 LOGE("failed to add src");
2552 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2553 LOGE("failed to add queue");
2557 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2558 LOGE("failed to link src and queue");
2562 /* create decoder */
2563 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2565 LOGE("failed to get srcpad of queue");
2569 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2570 _mmplayer_gst_create_decoder(player, srcpad, caps);
2572 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2573 LOGE("failed to create decoder");
2574 gst_object_unref(GST_OBJECT(srcpad));
2578 gst_object_unref(GST_OBJECT(srcpad));
2582 if (mainbin[src_id].gst) {
2583 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2584 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2585 gst_object_unref(mainbin[src_id].gst);
2586 mainbin[src_id].gst = NULL;
2589 if (mainbin[queue_id].gst) {
2590 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2591 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2592 gst_object_unref(mainbin[queue_id].gst);
2593 mainbin[queue_id].gst = NULL;
2600 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2602 GstPad *sinkpad = NULL;
2603 GstCaps *caps = NULL;
2604 GstElement *new_element = NULL;
2605 GstStructure *str = NULL;
2606 const gchar *name = NULL;
2608 mmplayer_t *player = (mmplayer_t *)data;
2612 MMPLAYER_RETURN_IF_FAIL(element && pad);
2613 MMPLAYER_RETURN_IF_FAIL(player &&
2615 player->pipeline->mainbin);
2617 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2618 * num_dynamic_pad will decreased after creating a sinkbin.
2620 player->num_dynamic_pad++;
2621 LOGD("stream count inc : %d", player->num_dynamic_pad);
2623 caps = gst_pad_query_caps(pad, NULL);
2624 MMPLAYER_CHECK_NULL(caps);
2626 str = gst_caps_get_structure(caps, 0);
2627 name = gst_structure_get_string(str, "media");
2629 LOGE("cannot get mimetype from structure.");
2633 if (strstr(name, "video")) {
2635 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2637 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2638 if (player->v_stream_caps) {
2639 gst_caps_unref(player->v_stream_caps);
2640 player->v_stream_caps = NULL;
2643 new_element = gst_element_factory_make("fakesink", NULL);
2644 player->num_dynamic_pad--;
2649 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2650 LOGE("failed to autoplug for caps");
2654 gst_caps_unref(caps);
2659 /* execute new_element if created*/
2661 LOGD("adding new element to pipeline");
2663 /* set state to READY before add to bin */
2664 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2666 /* add new element to the pipeline */
2667 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2668 LOGE("failed to add autoplug element to bin");
2672 /* get pad from element */
2673 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2675 LOGE("failed to get sinkpad from autoplug element");
2680 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2681 LOGE("failed to link autoplug element");
2685 gst_object_unref(sinkpad);
2688 /* run. setting PLAYING here since streaming source is live source */
2689 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2693 gst_caps_unref(caps);
2699 STATE_CHANGE_FAILED:
2701 /* FIXIT : take care if new_element has already added to pipeline */
2703 gst_object_unref(GST_OBJECT(new_element));
2706 gst_object_unref(GST_OBJECT(sinkpad));
2709 gst_caps_unref(caps);
2711 /* FIXIT : how to inform this error to MSL ????? */
2712 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2713 * then post an error to application
2718 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2720 mmplayer_t *player = (mmplayer_t *)data;
2724 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2725 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2726 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2727 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2729 * [1] audio and video will be dumped with filesink.
2730 * [2] autoplugging is done by just using pad caps.
2731 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2732 * and the video will be dumped via filesink.
2734 if (player->num_dynamic_pad == 0) {
2735 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2737 if (!_mmplayer_gst_remove_fakesink(player,
2738 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2739 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2740 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2741 * source element are not same. To overcome this situation, this function will called
2742 * several places and several times. Therefore, this is not an error case.
2747 /* create dot before error-return. for debugging */
2748 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2750 player->no_more_pad = TRUE;
2756 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2758 GstElement *element = NULL;
2759 gchar *user_agent = NULL;
2760 MMHandleType attrs = 0;
2763 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2765 /* get profile attribute */
2766 attrs = MMPLAYER_GET_ATTRS(player);
2768 LOGE("failed to get content attribute");
2772 element = gst_element_factory_make("rtspsrc", "rtsp source");
2774 LOGE("failed to create rtspsrc element");
2779 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2781 SECURE_LOGD("user_agent : %s", user_agent);
2783 /* setting property to streaming source */
2784 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2786 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2788 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2789 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2790 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2791 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2797 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2799 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2801 mmplayer_t *player = (mmplayer_t *)data;
2802 MMHandleType attrs = 0;
2803 gchar *user_agent, *cookies, **cookie_list;
2804 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2805 user_agent = cookies = NULL;
2809 MMPLAYER_RETURN_IF_FAIL(player);
2811 LOGD("source element %s", GST_ELEMENT_NAME(source));
2813 attrs = MMPLAYER_GET_ATTRS(player);
2815 LOGE("failed to get content attribute");
2819 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2820 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2822 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2823 http_timeout = player->ini.http_timeout;
2825 SECURE_LOGD("cookies : %s", cookies);
2826 SECURE_LOGD("user_agent : %s", user_agent);
2827 LOGD("timeout : %d", http_timeout);
2829 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2831 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2832 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2833 g_strfreev(cookie_list);
2837 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2843 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2845 mmplayer_t *player = (mmplayer_t *)data;
2846 gchar *user_agent = NULL;
2847 MMHandleType attrs = 0;
2850 MMPLAYER_RETURN_IF_FAIL(player);
2852 attrs = MMPLAYER_GET_ATTRS(player);
2854 LOGE("failed to get content attribute");
2858 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2860 SECURE_LOGD("user_agent : %s", user_agent);
2863 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2869 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2871 mmplayer_t *player = (mmplayer_t *)data;
2872 GstElement *source = NULL;
2875 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2877 g_object_get(orig, pspec->name, &source, NULL);
2879 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2880 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2882 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2883 __mmplayer_http_src_setup(source, data);
2884 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2885 __mmplayer_rtsp_src_setup(source, data);
2886 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2887 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2888 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2889 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2890 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2892 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2893 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2894 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2895 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2897 gst_object_unref (source);
2903 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2904 GstStream * stream, gpointer data)
2906 #define RET_SELECT 1
2908 #define RET_DEPENDS_ON_DECODEBIN -1
2910 GstStreamType stype = gst_stream_get_stream_type(stream);
2911 mmplayer_t *player = (mmplayer_t *)data;
2912 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2913 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2914 g_autofree gchar *caps_str = NULL;
2915 GstStructure *caps_structure = NULL;
2916 int stream_index = INVALID_TRACK_INDEX;
2917 int ret = MM_ERROR_NONE;
2919 LOGD("Stream type %s flags 0x%x",
2920 gst_stream_type_get_name(stype),
2921 gst_stream_get_stream_flags(stream));
2922 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2924 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
2927 caps_str = gst_caps_to_string(caps);
2928 caps_structure = gst_caps_get_structure(caps, 0);
2929 const gchar *mime = gst_structure_get_name(caps_structure);
2931 LOGD(" caps: %s", caps_str);
2933 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2934 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2935 LOGW("skip [%s] by unsupported codec keyword [%s]",
2936 mime, player->ini.unsupported_codec_keyword[idx]);
2938 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2942 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2943 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2944 LOGD("No caps info, depends on decodebin");
2945 _mmplayer_track_update_stream(player, type, stream);
2946 return RET_DEPENDS_ON_DECODEBIN;
2949 LOGD("No caps info, skip it");
2954 case GST_STREAM_TYPE_AUDIO:
2956 if (caps_structure) {
2957 gint samplerate = 0;
2960 gst_structure_get_int(caps_structure, "rate", &samplerate);
2961 gst_structure_get_int(caps_structure, "channels", &channels);
2962 if (samplerate == 0 && channels > 0) {
2963 LOGW("Skip corrupted audio stream");
2967 if (g_strrstr(caps_str, "mobile-xmf"))
2968 mm_player_set_attribute((MMHandleType)player, NULL,
2969 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2973 case GST_STREAM_TYPE_VIDEO:
2975 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2976 LOGD("do not support muti track video");
2980 // FIXME: it cause block during preparing
2981 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2984 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2985 /* don't make video because of not required */
2986 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2987 (!player->set_mode.video_export)) {
2988 LOGD("no need video decoding, skip video stream");
2993 if (caps_structure) {
2996 gst_structure_get_int(caps_structure, "width", &width);
2998 if (player->v_stream_caps) {
2999 gst_caps_unref(player->v_stream_caps);
3000 player->v_stream_caps = NULL;
3003 player->v_stream_caps = gst_caps_copy(caps);
3004 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3009 case GST_STREAM_TYPE_TEXT:
3012 LOGW("Skip not supported stream type");
3016 _mmplayer_track_update_stream(player, type, stream);
3018 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3020 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3021 (ret == MM_ERROR_NONE)) {
3022 player->track[type].active_track_index = stream_index;
3023 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3024 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3025 _mmplayer_set_audio_attrs(player, caps);
3029 if (player->track[type].active_track_index == stream_index) {
3030 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3034 LOGD("Skip stream");
3039 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3040 GstStream * stream, gpointer data)
3042 mmplayer_t *player = (mmplayer_t *)data;
3043 GstStreamType stype = gst_stream_get_stream_type(stream);
3046 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3048 LOGD("stream type %s", gst_stream_type_get_name(stype));
3050 /* public does not support audio hw decoder at the moment */
3052 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3053 LOGW("video decoder resource is already acquired, skip it.");
3057 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3058 LOGE("failed to acquire video decoder resource");
3061 player->interrupted_by_resource = FALSE;
3067 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3069 GstIterator *iter = NULL;
3070 GValue item = {0, };
3071 GstElement *ch_element = NULL;
3072 GstElementFactory *ch_factory = NULL;
3075 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3077 iter = gst_bin_iterate_recurse(bin);
3078 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3080 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3081 ch_element = g_value_get_object(&item);
3082 ch_factory = gst_element_get_factory(ch_element);
3083 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3084 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3085 LOGD("Find %s element", element_name);
3089 g_value_reset(&item);
3091 gst_iterator_free(iter);
3097 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3099 mmplayer_t *player = (mmplayer_t *)data;
3101 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3103 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3104 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3105 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3107 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3108 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3109 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3112 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3114 mmplayer_t *player = (mmplayer_t *)data;
3115 int video_codec_type = 0;
3116 int audio_codec_type = 0;
3118 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3120 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3121 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3123 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3125 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3126 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3127 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3128 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3130 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3131 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3135 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3137 gchar *factory_name = NULL;
3138 mmplayer_t *player = (mmplayer_t *)data;
3141 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3143 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3145 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3147 if (g_strrstr(factory_name, "urisourcebin")) {
3148 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3150 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3152 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3154 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3156 LOGW("failed to find decodebin3");
3158 } else if (g_strrstr(factory_name, "parsebin")) {
3159 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3160 __mmplayer_parsebin_setup(GST_BIN(element), data);
3162 _mmplayer_gst_element_added(child, element, data);
3167 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3171 MMPLAYER_RETURN_IF_FAIL(player);
3172 MMPLAYER_RETURN_IF_FAIL(removed_element);
3174 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3176 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3177 GList *node = player->signals[type];
3179 GList *next_node = node->next;
3180 mmplayer_signal_item_t *item = node->data;
3181 if (item && item->obj == G_OBJECT(removed_element)) {
3182 player->signals[type] = g_list_delete_link(player->signals[type], node);
3183 MMPLAYER_FREEIF(item);
3193 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3195 mmplayer_t *player = (mmplayer_t *)data;
3199 MMPLAYER_RETURN_IF_FAIL(player);
3201 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3203 __mmplayer_delete_signal_connection(player, element);
3209 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3211 GstElement *uridecodebin3 = NULL;
3214 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3216 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3217 if (!uridecodebin3) {
3218 LOGE("failed to create uridecodebin3");
3223 SECURE_LOGD("uri : %s", player->profile.uri);
3225 /* setting property to streaming source */
3226 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3227 "message-forward", TRUE,
3228 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3229 "use-buffering", TRUE, NULL);
3231 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3232 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3234 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3235 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3237 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3238 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3240 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3241 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3243 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3244 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3246 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3247 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3249 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3250 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3252 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3253 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3255 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3256 LOGW("[DASH] this is still experimental feature");
3259 return uridecodebin3;
3263 __mmplayer_gst_make_http_src(mmplayer_t *player)
3265 #define MAX_RETRY_COUNT 10
3266 GstElement *element = NULL;
3267 MMHandleType attrs = 0;
3268 gchar *user_agent, *cookies, **cookie_list;
3269 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3271 user_agent = cookies = NULL;
3275 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3277 /* get profile attribute */
3278 attrs = MMPLAYER_GET_ATTRS(player);
3280 LOGE("failed to get content attribute");
3284 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3286 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3288 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3293 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3294 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3296 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3297 http_timeout = player->ini.http_timeout;
3300 SECURE_LOGD("location : %s", player->profile.uri);
3301 SECURE_LOGD("cookies : %s", cookies);
3302 SECURE_LOGD("user_agent : %s", user_agent);
3303 LOGD("timeout : %d", http_timeout);
3305 /* setting property to streaming source */
3306 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3307 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3308 "retries", MAX_RETRY_COUNT, NULL);
3310 /* parsing cookies */
3311 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3312 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3313 g_strfreev(cookie_list);
3317 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3319 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3320 LOGW("[DASH] this is still experimental feature");
3327 __mmplayer_gst_make_file_src(mmplayer_t *player)
3329 GstElement *element = NULL;
3332 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3334 LOGD("using filesrc for 'file://' handler");
3335 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3336 LOGE("failed to get storage info");
3340 element = gst_element_factory_make("filesrc", "source");
3342 LOGE("failed to create filesrc");
3346 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3353 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3355 mmplayer_t *player = (mmplayer_t *)data;
3357 g_return_val_if_fail(player, FALSE);
3358 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3359 gst_message_ref(msg);
3361 g_mutex_lock(&player->bus_msg_q_lock);
3362 g_queue_push_tail(player->bus_msg_q, msg);
3363 g_mutex_unlock(&player->bus_msg_q_lock);
3365 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3366 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3367 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3371 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3373 mmplayer_t *player = (mmplayer_t *)(data);
3374 GstMessage *msg = NULL;
3377 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3379 player->pipeline->mainbin &&
3380 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3383 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3385 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3386 while (!player->bus_msg_thread_exit) {
3387 g_mutex_lock(&player->bus_msg_q_lock);
3388 msg = g_queue_pop_head(player->bus_msg_q);
3389 g_mutex_unlock(&player->bus_msg_q_lock);
3391 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3394 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3395 /* handle the gst msg */
3396 __mmplayer_gst_bus_msg_callback(msg, player);
3397 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3398 gst_message_unref(msg);
3401 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3408 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3410 gint64 dur_nsec = 0;
3411 gint64 pos_nsec = 0;
3414 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3416 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3417 return MM_ERROR_NONE;
3419 /* NOTE : duration cannot be zero except live streaming.
3420 * Since some element could have some timing problem with querying duration, try again.
3422 if (player->duration == 0) {
3423 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3424 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3425 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3426 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3427 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3428 player->pending_seek.is_pending = true;
3429 player->pending_seek.pos = position;
3430 player->seek_state = MMPLAYER_SEEK_NONE;
3431 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3432 return MM_ERROR_PLAYER_NO_OP;
3434 player->seek_state = MMPLAYER_SEEK_NONE;
3435 return MM_ERROR_PLAYER_SEEK;
3438 player->duration = dur_nsec;
3441 if (player->duration > 0 && player->duration < position) {
3442 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3443 return MM_ERROR_INVALID_ARGUMENT;
3446 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3447 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3448 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3449 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3450 player->seek_state = MMPLAYER_SEEK_NONE;
3451 return MM_ERROR_PLAYER_NO_OP;
3456 return MM_ERROR_NONE;
3460 __mmplayer_gst_check_seekable(mmplayer_t *player)
3462 GstQuery *query = NULL;
3463 gboolean seekable = FALSE;
3465 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3469 query = gst_query_new_seeking(GST_FORMAT_TIME);
3470 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3471 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3472 gst_query_unref(query);
3475 LOGW("non-seekable content");
3476 player->seek_state = MMPLAYER_SEEK_NONE;
3480 LOGW("failed to get seeking query");
3481 gst_query_unref(query); /* keep seeking operation */
3488 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3490 GstState element_state = GST_STATE_VOID_PENDING;
3491 GstState element_pending_state = GST_STATE_VOID_PENDING;
3492 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3496 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3497 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3499 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3502 ret = gst_element_set_state(element, state);
3503 if (ret == GST_STATE_CHANGE_FAILURE) {
3504 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3506 /* dump state of all element */
3507 _mmplayer_dump_pipeline_state(player);
3509 return MM_ERROR_PLAYER_INTERNAL;
3512 /* return here so state transition to be done in async mode */
3514 LOGD("async state transition. not waiting for state complete.");
3515 return MM_ERROR_NONE;
3518 /* wait for state transition */
3519 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3520 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3521 LOGE("failed to change [%s] element state to [%s] within %d sec",
3522 GST_ELEMENT_NAME(element),
3523 gst_element_state_get_name(state), timeout);
3525 LOGE(" [%s] state : %s pending : %s",
3526 GST_ELEMENT_NAME(element),
3527 gst_element_state_get_name(element_state),
3528 gst_element_state_get_name(element_pending_state));
3530 /* dump state of all element */
3531 _mmplayer_dump_pipeline_state(player);
3533 return MM_ERROR_PLAYER_INTERNAL;
3536 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3540 return MM_ERROR_NONE;
3544 _mmplayer_gst_start(mmplayer_t *player)
3546 int ret = MM_ERROR_NONE;
3547 gboolean async = FALSE;
3551 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3553 /* NOTE : if SetPosition was called before Start. do it now
3554 * streaming doesn't support it. so it should be always sync
3555 * !!create one more api to check if there is pending seek rather than checking variables
3557 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3558 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3559 ret = _mmplayer_gst_pause(player, FALSE);
3560 if (ret != MM_ERROR_NONE) {
3561 LOGE("failed to set state to PAUSED for pending seek");
3565 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3566 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3567 LOGW("failed to seek pending position. starting from the begin of content");
3570 LOGD("current state before doing transition");
3571 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3572 MMPLAYER_PRINT_STATE(player);
3574 /* set pipeline state to PLAYING */
3575 ret = _mmplayer_gst_set_state(player,
3576 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3577 if (ret != MM_ERROR_NONE) {
3578 LOGE("failed to set state to PLAYING");
3582 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3584 /* generating debug info before returning error */
3585 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3593 _mmplayer_gst_stop(mmplayer_t *player)
3595 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3596 MMHandleType attrs = 0;
3597 gboolean rewind = FALSE;
3599 int ret = MM_ERROR_NONE;
3603 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3604 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3606 LOGD("current state before doing transition");
3607 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3608 MMPLAYER_PRINT_STATE(player);
3610 attrs = MMPLAYER_GET_ATTRS(player);
3612 LOGE("cannot get content attribute");
3613 return MM_ERROR_PLAYER_INTERNAL;
3616 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3617 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3619 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3620 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3623 if (player->es_player_push_mode)
3624 /* disable the async state transition because there could be no data in the pipeline */
3625 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3628 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3630 if (player->es_player_push_mode) {
3631 /* enable the async state transition as default operation */
3632 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3635 /* return if set_state has failed */
3636 if (ret != MM_ERROR_NONE) {
3637 LOGE("failed to set state.");
3643 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3644 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3645 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3646 LOGW("failed to rewind");
3647 ret = MM_ERROR_PLAYER_SEEK;
3652 player->sent_bos = FALSE;
3654 if (player->es_player_push_mode) //for cloudgame
3657 /* wait for seek to complete */
3658 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3659 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3660 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3662 LOGE("fail to stop player.");
3663 ret = MM_ERROR_PLAYER_INTERNAL;
3664 _mmplayer_dump_pipeline_state(player);
3667 /* generate dot file if enabled */
3668 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3676 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3678 int ret = MM_ERROR_NONE;
3682 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3683 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3685 LOGD("current state before doing transition");
3686 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3687 MMPLAYER_PRINT_STATE(player);
3689 /* set pipeline status to PAUSED */
3690 ret = _mmplayer_gst_set_state(player,
3691 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3696 if (ret != MM_ERROR_NONE) {
3697 GstMessage *msg = NULL;
3698 GTimer *timer = NULL;
3699 gdouble MAX_TIMEOUT_SEC = 3;
3701 LOGE("failed to set state to PAUSED");
3703 if (!player->bus_watcher) {
3704 LOGE("there is no bus msg thread. pipeline is shutting down.");
3708 if (player->msg_posted) {
3709 LOGE("error msg is already posted.");
3713 timer = g_timer_new();
3714 g_timer_start(timer);
3716 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3719 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3721 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3722 GError *error = NULL;
3724 /* parse error code */
3725 gst_message_parse_error(msg, &error, NULL);
3727 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3728 /* Note : the streaming error from the streaming source is handled
3729 * using __mmplayer_handle_streaming_error.
3731 __mmplayer_handle_streaming_error(player, msg, error);
3734 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3736 if (error->domain == GST_STREAM_ERROR)
3737 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3738 else if (error->domain == GST_RESOURCE_ERROR)
3739 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3740 else if (error->domain == GST_LIBRARY_ERROR)
3741 ret = __mmplayer_gst_handle_library_error(player, error->code);
3742 else if (error->domain == GST_CORE_ERROR)
3743 ret = __mmplayer_gst_handle_core_error(player, error->code);
3745 g_error_free(error);
3747 player->msg_posted = TRUE;
3749 gst_message_unref(msg);
3751 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3753 gst_object_unref(bus);
3754 g_timer_stop(timer);
3755 g_timer_destroy(timer);
3760 if (MMPLAYER_USE_DECODEBIN(player)) {
3761 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3762 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3763 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3766 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3769 /* generate dot file before returning error */
3770 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3778 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3780 int ret = MM_ERROR_NONE;
3785 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3786 MM_ERROR_PLAYER_NOT_INITIALIZED);
3788 LOGD("current state before doing transition");
3789 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3790 MMPLAYER_PRINT_STATE(player);
3793 LOGD("do async state transition to PLAYING");
3795 /* set pipeline state to PLAYING */
3796 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3798 ret = _mmplayer_gst_set_state(player,
3799 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3800 if (ret != MM_ERROR_NONE) {
3801 LOGE("failed to set state to PLAYING");
3806 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3809 /* generate dot file */
3810 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3817 /* sending event to one of sinkelements */
3819 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3821 GstEvent *event2 = NULL;
3822 GList *sinks = NULL;
3823 gboolean res = FALSE;
3826 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3827 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3829 /* While adding subtitles in live feeds seek is getting called.
3830 Adding defensive check in framework layer.*/
3831 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3832 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3833 LOGE("Should not send seek event during live playback");
3838 if (player->play_subtitle)
3839 event2 = gst_event_copy((const GstEvent *)event);
3841 sinks = player->sink_elements;
3843 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3845 if (GST_IS_ELEMENT(sink)) {
3846 /* keep ref to the event */
3847 gst_event_ref(event);
3849 if ((res = gst_element_send_event(sink, event))) {
3850 LOGD("sending event[%s] to sink element [%s] success!",
3851 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3853 /* rtsp case, async_done is not called after seek during pause state */
3854 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3855 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3856 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3857 LOGD("RTSP seek completed, after pause state..");
3858 player->seek_state = MMPLAYER_SEEK_NONE;
3859 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3865 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3866 sinks = g_list_next(sinks);
3873 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3874 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3877 sinks = g_list_next(sinks);
3880 /* Note : Textbin is not linked to the video or audio bin.
3881 * It needs to send the event to the text sink separately.
3883 if (player->play_subtitle && player->pipeline) {
3884 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3886 if (GST_IS_ELEMENT(text_sink)) {
3887 /* keep ref to the event */
3888 gst_event_ref(event2);
3890 if ((res = gst_element_send_event(text_sink, event2)))
3891 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3892 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3894 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3895 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3897 gst_event_unref(event2);
3901 gst_event_unref(event);
3909 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3910 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3911 gint64 cur, GstSeekType stop_type, gint64 stop)
3913 GstEvent *event = NULL;
3914 gboolean result = FALSE;
3918 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3920 if (player->pipeline && player->pipeline->textbin)
3921 __mmplayer_drop_subtitle(player, FALSE);
3923 event = gst_event_new_seek(rate, format, flags, cur_type,
3924 cur, stop_type, stop);
3926 result = _mmplayer_gst_send_event_to_sink(player, event);
3934 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3936 int ret = MM_ERROR_NONE;
3937 gint64 pos_nsec = 0;
3938 gboolean accurate = FALSE;
3939 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3942 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3943 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3945 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3946 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3949 ret = __mmplayer_gst_check_position(player, position);
3950 if (ret != MM_ERROR_NONE) {
3951 LOGW("result of check position info 0x%X", ret);
3952 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3955 if (!__mmplayer_gst_check_seekable(player))
3956 return MM_ERROR_PLAYER_NO_OP;
3958 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3959 position, player->playback_rate, player->duration);
3961 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3962 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3963 This causes problem is position calculation during normal pause resume scenarios also.
3964 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3965 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3966 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3967 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3968 LOGW("getting current position failed in seek");
3970 player->last_position = pos_nsec;
3971 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3974 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3975 LOGD("not completed seek");
3976 return MM_ERROR_PLAYER_DOING_SEEK;
3979 if (!internal_called)
3980 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3982 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3983 that's why set position through property. */
3984 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3985 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3986 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3987 (!player->videodec_linked) && (!player->audiodec_linked)) {
3989 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3990 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3992 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3993 player->seek_state = MMPLAYER_SEEK_NONE;
3994 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3996 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3998 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4000 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4002 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4003 GST_FORMAT_TIME, seek_flags,
4004 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4005 LOGE("failed to set position");
4010 /* NOTE : store last seeking point to overcome some bad operation
4011 * (returning zero when getting current position) of some elements
4013 player->last_position = position;
4015 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4016 if (player->playback_rate > 1.0)
4017 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4019 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4020 LOGD("buffering should be reset after seeking");
4021 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4022 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4026 return MM_ERROR_NONE;
4029 player->pending_seek.is_pending = true;
4030 player->pending_seek.pos = position;
4032 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4033 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4034 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4035 player->pending_seek.pos);
4037 return MM_ERROR_NONE;
4040 player->seek_state = MMPLAYER_SEEK_NONE;
4041 return MM_ERROR_PLAYER_SEEK;
4045 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4047 #define TRICKPLAY_OFFSET GST_MSECOND
4049 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4050 gint64 pos_nsec = 0;
4051 gboolean ret = TRUE;
4053 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4054 MM_ERROR_PLAYER_NOT_INITIALIZED);
4056 current_state = MMPLAYER_CURRENT_STATE(player);
4058 /* NOTE : query position except paused state to overcome some bad operation
4059 * please refer to below comments in details
4061 if (current_state != MM_PLAYER_STATE_PAUSED)
4062 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4064 /* NOTE : get last point to overcome some bad operation of some elements
4065 *(returning zero when getting current position in paused state
4066 * and when failed to get position during seeking
4068 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4069 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4071 if (player->playback_rate < 0.0)
4072 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4074 pos_nsec = player->last_position;
4077 pos_nsec = player->last_position;
4079 player->last_position = pos_nsec;
4081 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4084 if (player->duration > 0 && pos_nsec > player->duration)
4085 pos_nsec = player->duration;
4087 player->last_position = pos_nsec;
4090 *position = pos_nsec;
4092 return MM_ERROR_NONE;
4096 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4098 #define STREAMING_IS_FINISHED 0
4099 #define BUFFERING_MAX_PER 100
4100 #define DEFAULT_PER_VALUE -1
4101 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4103 mmplayer_gst_element_t *mainbin = NULL;
4104 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4105 gint64 buffered_total = 0;
4106 gint64 position = 0;
4107 gint buffered_sec = -1;
4108 GstBufferingMode mode = GST_BUFFERING_STREAM;
4109 gint64 content_size_time = player->duration;
4110 guint64 content_size_bytes = player->http_content_size;
4112 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4114 player->pipeline->mainbin,
4115 MM_ERROR_PLAYER_NOT_INITIALIZED);
4117 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4122 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4123 /* and rtsp is not ready yet. */
4124 LOGW("it's only used for http streaming case");
4125 return MM_ERROR_PLAYER_NO_OP;
4128 if (content_size_time <= 0 || content_size_bytes <= 0) {
4129 LOGW("there is no content size");
4130 return MM_ERROR_NONE;
4133 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4134 LOGW("fail to get current position");
4135 return MM_ERROR_NONE;
4138 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4139 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4141 mainbin = player->pipeline->mainbin;
4142 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4144 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4145 GstQuery *query = NULL;
4146 gint byte_in_rate = 0, byte_out_rate = 0;
4147 gint64 estimated_total = 0;
4149 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4150 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4151 LOGW("fail to get buffering query from queue2");
4153 gst_query_unref(query);
4154 return MM_ERROR_NONE;
4157 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4158 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4160 if (mode == GST_BUFFERING_STREAM) {
4161 /* using only queue in case of push mode(ts / mp3) */
4162 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4163 GST_FORMAT_BYTES, &buffered_total)) {
4164 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4165 end_per = 100 * buffered_total / content_size_bytes;
4168 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4170 guint num_of_ranges = 0;
4171 gint64 start_byte = 0, stop_byte = 0;
4173 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4174 if (estimated_total != STREAMING_IS_FINISHED) {
4175 /* buffered size info from queue2 */
4176 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4177 for (idx = 0; idx < num_of_ranges; idx++) {
4178 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4179 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4181 buffered_total += (stop_byte - start_byte);
4184 end_per = BUFFERING_MAX_PER;
4187 gst_query_unref(query);
4190 if (end_per == DEFAULT_PER_VALUE) {
4191 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4193 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4195 /* buffered size info from multiqueue */
4196 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4197 guint curr_size_bytes = 0;
4198 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4199 "curr-size-bytes", &curr_size_bytes, NULL);
4200 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4201 buffered_total += (gint64)curr_size_bytes;
4204 if (avg_byterate > 0)
4205 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4206 else if (player->total_maximum_bitrate > 0)
4207 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4208 else if (player->total_bitrate > 0)
4209 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4211 if (buffered_sec >= 0)
4212 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4216 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4217 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4219 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4220 buffered_total, buffered_sec, *start_pos, *end_pos);
4222 return MM_ERROR_NONE;
4226 _mmplayer_gst_create_source(mmplayer_t *player)
4228 GstElement *element = NULL;
4231 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4232 player->pipeline->mainbin, NULL);
4234 /* setup source for gapless play */
4235 switch (player->profile.uri_type) {
4237 case MM_PLAYER_URI_TYPE_FILE:
4238 element = __mmplayer_gst_make_file_src(player);
4240 case MM_PLAYER_URI_TYPE_URL_HTTP:
4241 element = __mmplayer_gst_make_http_src(player);
4244 LOGE("not support uri type %d", player->profile.uri_type);
4249 LOGE("failed to create source element");
4258 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4262 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4264 SECURE_LOGD("uri : %s", player->profile.uri);
4266 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4268 if ((player->v_stream_caps) &&
4269 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4270 return MM_ERROR_PLAYER_INTERNAL;
4272 if ((player->a_stream_caps) &&
4273 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4274 return MM_ERROR_PLAYER_INTERNAL;
4276 if ((player->s_stream_caps) &&
4277 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4278 return MM_ERROR_PLAYER_INTERNAL;
4281 return MM_ERROR_NONE;
4285 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4287 mmplayer_gst_element_t *mainbin = NULL;
4288 GstElement *autoplug_elem = NULL;
4291 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4292 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4294 mainbin = player->pipeline->mainbin;
4296 LOGD("uri type %d", player->profile.uri_type);
4298 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4299 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4300 return MM_ERROR_PLAYER_INTERNAL;
4303 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4304 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4307 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4308 if (!autoplug_elem) {
4309 LOGE("failed to create uridecodebin3 element");
4313 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4314 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4315 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4317 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4318 LOGE("failed to add uridecodebin to pipeline");
4322 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4323 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4324 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4326 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4327 LOGE("failed to create fakesink");
4330 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4332 /* take ownership of fakesink. we are reusing it */
4333 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4335 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4336 LOGE("failed to add fakesink to bin");
4337 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4342 return MM_ERROR_NONE;
4346 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4347 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4349 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4350 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4352 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4353 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4355 return MM_ERROR_PLAYER_INTERNAL;
4359 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4361 mmplayer_gst_element_t *mainbin = NULL;
4362 GstElement *src_elem = NULL;
4363 GstElement *autoplug_elem = NULL;
4364 GList *element_bucket = NULL;
4365 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4368 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4369 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4371 LOGD("uri type %d", player->profile.uri_type);
4373 /* create source element */
4374 switch (player->profile.uri_type) {
4375 case MM_PLAYER_URI_TYPE_URL_RTSP:
4376 src_elem = __mmplayer_gst_make_rtsp_src(player);
4378 case MM_PLAYER_URI_TYPE_URL_HTTP:
4379 src_elem = __mmplayer_gst_make_http_src(player);
4381 case MM_PLAYER_URI_TYPE_FILE:
4382 src_elem = __mmplayer_gst_make_file_src(player);
4384 case MM_PLAYER_URI_TYPE_SS:
4386 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4387 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4389 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4393 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4394 LOGD("get timeout from ini");
4395 http_timeout = player->ini.http_timeout;
4398 /* setting property to streaming source */
4399 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4402 case MM_PLAYER_URI_TYPE_MEM:
4404 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4406 src_elem = gst_element_factory_make("appsrc", "mem-source");
4408 LOGE("failed to create appsrc element");
4412 g_object_set(src_elem, "stream-type", stream_type,
4413 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4415 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4416 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4417 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4418 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4422 LOGE("not support uri type");
4427 LOGE("failed to create source element");
4428 return MM_ERROR_PLAYER_INTERNAL;
4431 mainbin = player->pipeline->mainbin;
4433 /* take source element */
4434 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4436 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4437 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4438 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4440 /* create next element for auto-plugging */
4441 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4442 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4443 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4444 if (!autoplug_elem) {
4445 LOGE("failed to create typefind element");
4449 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4450 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4451 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4452 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4453 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4454 if (!autoplug_elem) {
4455 LOGE("failed to create decodebin");
4459 /* default size of mq in decodebin is 2M
4460 * but it can cause blocking issue during seeking depends on content. */
4461 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4464 if (autoplug_elem) {
4465 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4466 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4467 mainbin[autoplug_elem_id].gst = autoplug_elem;
4469 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4472 /* add elements to pipeline */
4473 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4474 LOGE("failed to add elements to pipeline");
4478 /* linking elements in the bucket by added order. */
4479 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4480 LOGE("failed to link some elements");
4484 /* FIXME: need to check whether this is required or not. */
4485 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4486 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4487 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4488 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4489 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4491 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4492 LOGE("failed to create fakesink");
4495 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4497 /* take ownership of fakesink. we are reusing it */
4498 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4500 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4501 LOGE("failed to add fakesink to bin");
4502 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4507 g_list_free(element_bucket);
4510 return MM_ERROR_NONE;
4513 g_list_free(element_bucket);
4515 if (mainbin[MMPLAYER_M_SRC].gst)
4516 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4518 if (mainbin[autoplug_elem_id].gst)
4519 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4521 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4522 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4524 mainbin[MMPLAYER_M_SRC].gst = NULL;
4525 mainbin[autoplug_elem_id].gst = NULL;
4526 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4528 return MM_ERROR_PLAYER_INTERNAL;
4532 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4535 mmplayer_gst_element_t *mainbin = NULL;
4538 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4539 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4541 mainbin = player->pipeline->mainbin;
4543 /* connect bus callback */
4544 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4546 LOGE("cannot get bus from pipeline");
4547 return MM_ERROR_PLAYER_INTERNAL;
4550 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4551 (GstBusFunc)__mmplayer_gst_msg_push, player,
4552 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4553 if (player->bus_watcher == 0) {
4554 LOGE("failed to add bus watch");
4555 return MM_ERROR_PLAYER_INTERNAL;
4558 g_mutex_init(&player->bus_watcher_mutex);
4559 g_cond_init(&player->bus_watcher_cond);
4561 player->context.thread_default = g_main_context_get_thread_default();
4562 if (player->context.thread_default == NULL) {
4563 player->context.thread_default = g_main_context_default();
4564 LOGD("thread-default context is the global default context");
4566 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4568 /* set sync handler to get tag synchronously */
4569 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4570 gst_object_unref(GST_OBJECT(bus));
4572 /* create gst bus_msb_cb thread */
4573 g_mutex_init(&player->bus_msg_thread_mutex);
4574 g_cond_init(&player->bus_msg_thread_cond);
4575 player->bus_msg_thread_exit = FALSE;
4576 player->bus_msg_thread =
4577 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4578 if (!player->bus_msg_thread) {
4579 LOGE("failed to create gst BUS msg thread");
4580 g_mutex_clear(&player->bus_msg_thread_mutex);
4581 g_cond_clear(&player->bus_msg_thread_cond);
4582 return MM_ERROR_PLAYER_INTERNAL;
4586 return MM_ERROR_NONE;
4590 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4592 int ret = MM_ERROR_NONE;
4593 mmplayer_gst_element_t *mainbin = NULL;
4594 MMMessageParamType msg_param = {0,};
4595 GstElement *element = NULL;
4596 MMHandleType attrs = 0;
4598 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4602 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4603 LOGE("player is not initialized");
4607 mainbin = player->pipeline->mainbin;
4608 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4610 attrs = MMPLAYER_GET_ATTRS(player);
4612 LOGE("fail to get attributes");
4616 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4618 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4619 LOGE("failed to parse profile");
4620 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4624 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4625 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4626 LOGE("dash or hls is not supportable");
4627 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4631 if (!MMPLAYER_USE_DECODEBIN(player)) {
4632 ret = _mmplayer_gst_build_pipeline_with_src(player);
4633 if (ret != MM_ERROR_NONE)
4636 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4637 LOGE("Failed to change state of uridecodebin3 element");
4643 element = _mmplayer_gst_create_source(player);
4645 LOGE("no source element was created");
4649 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4650 LOGE("failed to add source element to pipeline");
4651 gst_object_unref(GST_OBJECT(element));
4656 /* take source element */
4657 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4658 mainbin[MMPLAYER_M_SRC].gst = element;
4662 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4663 if (player->streamer == NULL) {
4664 player->streamer = _mm_player_streaming_create();
4665 _mm_player_streaming_initialize(player->streamer, TRUE);
4668 elem_idx = MMPLAYER_M_TYPEFIND;
4669 element = gst_element_factory_make("typefind", "typefinder");
4670 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4671 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4673 elem_idx = MMPLAYER_M_AUTOPLUG;
4674 element = _mmplayer_gst_make_decodebin(player);
4677 /* check autoplug element is OK */
4679 LOGE("can not create element(%d)", elem_idx);
4683 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4684 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4685 gst_object_unref(GST_OBJECT(element));
4690 mainbin[elem_idx].id = elem_idx;
4691 mainbin[elem_idx].gst = element;
4693 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4694 LOGE("Failed to link src - autoplug(or typefind)");
4698 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4699 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4700 LOGE("Failed to change state of src element");
4704 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4705 LOGE("Failed to change state of decodebin");
4710 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4711 LOGE("Failed to change state of src element");
4716 player->gapless.stream_changed = TRUE;
4717 player->gapless.running = TRUE;
4723 _mmplayer_set_reconfigure_state(player, FALSE);
4724 if (!player->msg_posted) {
4725 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4726 player->msg_posted = TRUE;