4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
58 /* check whether the error is posted from not-activated track or not */
60 gint active_index = 0;
62 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
64 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
65 LOGD("current active pad index -%d", active_index);
67 if (src_element_name) {
70 if (player->audio_decoders) {
71 GList *adec = player->audio_decoders;
72 for (; adec ; adec = g_list_next(adec)) {
73 gchar *name = adec->data;
75 LOGD("found audio decoder name = %s", name);
76 if (g_strrstr(name, src_element_name)) {
83 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
86 if (active_index != msg_src_pos) {
87 LOGD("skip error because error is posted from no activated track");
95 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
97 /* Demuxer can't parse one track because it's corrupted.
98 * So, the decoder for it is not linked.
99 * But, it has one playable track.
101 if (g_strrstr(klass, "Demux")) {
102 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
103 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
104 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
105 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
107 if (player->pipeline->audiobin) { // PCM
108 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
110 LOGD("not found any available codec. Player should be destroyed.");
111 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
116 return MM_ERROR_PLAYER_INVALID_STREAM;
120 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
122 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
123 LOGE("Not supported subtitle.");
124 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
126 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
130 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
132 /* Decoder Custom Message */
133 if (!strstr(error->message, "ongoing"))
134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
136 if (strncasecmp(klass, "audio", 5)) {
137 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
138 LOGD("Video can keep playing.");
139 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
141 } else if (strncasecmp(klass, "video", 5)) {
142 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
143 LOGD("Audio can keep playing.");
144 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
148 LOGD("not found any available codec. Player should be destroyed.");
149 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
153 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
155 if (strstr(error->message, "rights expired"))
156 return MM_ERROR_PLAYER_DRM_EXPIRED;
157 else if (strstr(error->message, "no rights"))
158 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
159 else if (strstr(error->message, "has future rights"))
160 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
161 else if (strstr(error->message, "opl violation"))
162 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
164 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
167 /* NOTE : decide gstreamer state whether there is some playable track or not. */
169 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
171 gchar *src_element_name = NULL;
172 GstElement *src_element = NULL;
173 GstElementFactory *factory = NULL;
174 const gchar *klass = NULL;
178 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
179 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
180 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
181 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
183 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
185 src_element = GST_ELEMENT_CAST(message->src);
186 src_element_name = GST_ELEMENT_NAME(src_element);
187 if (!src_element_name)
188 return MM_ERROR_PLAYER_INTERNAL;
190 factory = gst_element_get_factory(src_element);
192 return MM_ERROR_PLAYER_INTERNAL;
194 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
196 return MM_ERROR_PLAYER_INTERNAL;
198 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
199 error->code, error->message, src_element_name, klass);
201 if (MMPLAYER_USE_DECODEBIN(player) &&
202 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
203 return MM_ERROR_NONE;
205 switch (error->code) {
206 case GST_STREAM_ERROR_DECODE:
207 return __mmplayer_gst_transform_error_decode(player, klass);
208 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
209 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
210 case GST_STREAM_ERROR_WRONG_TYPE:
211 return __mmplayer_gst_transform_error_type(player, src_element);
212 case GST_STREAM_ERROR_FAILED:
213 return __mmplayer_gst_transform_error_failed(player, klass, error);
214 case GST_STREAM_ERROR_DECRYPT:
215 case GST_STREAM_ERROR_DECRYPT_NOKEY:
216 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
217 return __mmplayer_gst_transform_error_decrypt(player, error);
224 return MM_ERROR_PLAYER_INVALID_STREAM;
228 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
230 gint trans_err = MM_ERROR_NONE;
234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 case GST_CORE_ERROR_MISSING_PLUGIN:
238 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
239 case GST_CORE_ERROR_STATE_CHANGE:
240 case GST_CORE_ERROR_SEEK:
241 case GST_CORE_ERROR_NOT_IMPLEMENTED:
242 case GST_CORE_ERROR_FAILED:
243 case GST_CORE_ERROR_TOO_LAZY:
244 case GST_CORE_ERROR_PAD:
245 case GST_CORE_ERROR_THREAD:
246 case GST_CORE_ERROR_NEGOTIATION:
247 case GST_CORE_ERROR_EVENT:
248 case GST_CORE_ERROR_CAPS:
249 case GST_CORE_ERROR_TAG:
250 case GST_CORE_ERROR_CLOCK:
251 case GST_CORE_ERROR_DISABLED:
253 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
263 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
265 gint trans_err = MM_ERROR_NONE;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
272 case GST_LIBRARY_ERROR_FAILED:
273 case GST_LIBRARY_ERROR_TOO_LAZY:
274 case GST_LIBRARY_ERROR_INIT:
275 case GST_LIBRARY_ERROR_SHUTDOWN:
276 case GST_LIBRARY_ERROR_SETTINGS:
277 case GST_LIBRARY_ERROR_ENCODE:
279 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
289 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
291 gint trans_err = MM_ERROR_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
298 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
299 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
301 case GST_RESOURCE_ERROR_NOT_FOUND:
302 case GST_RESOURCE_ERROR_OPEN_READ:
303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
304 || MMPLAYER_IS_RTSP_STREAMING(player)) {
305 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
308 case GST_RESOURCE_ERROR_READ:
309 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
310 || MMPLAYER_IS_RTSP_STREAMING(player)) {
311 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
313 } else if (message != NULL && message->src != NULL) {
314 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
315 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
317 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
318 path_type = MMPLAYER_PATH_VOD;
319 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
320 path_type = MMPLAYER_PATH_TEXT;
322 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
323 /* check storage state */
324 storage_get_state(player->storage_info[path_type].id, &storage_state);
325 player->storage_info[path_type].state = storage_state;
326 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
329 case GST_RESOURCE_ERROR_WRITE:
330 case GST_RESOURCE_ERROR_FAILED:
331 case GST_RESOURCE_ERROR_SEEK:
332 case GST_RESOURCE_ERROR_TOO_LAZY:
333 case GST_RESOURCE_ERROR_BUSY:
334 case GST_RESOURCE_ERROR_OPEN_WRITE:
335 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
336 case GST_RESOURCE_ERROR_CLOSE:
337 case GST_RESOURCE_ERROR_SYNC:
338 case GST_RESOURCE_ERROR_SETTINGS:
340 trans_err = MM_ERROR_PLAYER_INTERNAL;
350 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
352 gint trans_err = MM_ERROR_NONE;
356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
358 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
360 switch (error->code) {
361 case GST_STREAM_ERROR_FAILED:
362 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
363 case GST_STREAM_ERROR_DECODE:
364 case GST_STREAM_ERROR_WRONG_TYPE:
365 case GST_STREAM_ERROR_DECRYPT:
366 case GST_STREAM_ERROR_DECRYPT_NOKEY:
367 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
368 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
371 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
372 case GST_STREAM_ERROR_TOO_LAZY:
373 case GST_STREAM_ERROR_ENCODE:
374 case GST_STREAM_ERROR_DEMUX:
375 case GST_STREAM_ERROR_MUX:
376 case GST_STREAM_ERROR_FORMAT:
378 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
388 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
390 MMMessageParamType msg_param;
391 gchar *msg_src_element;
395 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
396 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
398 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
400 memset(&msg_param, 0, sizeof(MMMessageParamType));
402 if (error->domain == GST_CORE_ERROR) {
403 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
404 } else if (error->domain == GST_LIBRARY_ERROR) {
405 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
406 } else if (error->domain == GST_RESOURCE_ERROR) {
407 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
408 } else if (error->domain == GST_STREAM_ERROR) {
409 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
411 LOGW("This error domain is not defined.");
413 /* we treat system error as an internal error */
414 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
418 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
420 msg_param.data = (void *)error->message;
422 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
423 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
427 if (msg_param.code == MM_ERROR_NONE)
430 /* skip error to avoid duplicated posting */
431 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
432 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
433 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
434 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
436 /* The error will be handled by mused.
437 * @ref _mmplayer_manage_external_storage_state() */
439 LOGW("storage is removed, skip error post");
443 /* post error to application */
444 if (!player->msg_posted) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
446 /* don't post more if one was sent already */
447 player->msg_posted = TRUE;
449 LOGD("skip error post because it's sent already.");
458 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
461 MMMessageParamType msg_param = {0, };
462 gchar *msg_src_element = NULL;
466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
467 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
468 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
470 switch (error->code) {
471 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
472 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
474 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
475 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
477 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
478 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
480 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
481 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
483 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
484 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
486 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
487 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
489 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
490 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
492 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
493 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
495 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
498 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
501 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
504 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
507 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
510 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
513 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
516 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
519 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
522 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
525 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
528 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
531 case MMPLAYER_STREAMING_ERROR_GONE:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
534 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
540 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
543 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
546 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
549 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
552 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
555 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
558 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
561 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
564 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
567 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
570 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
573 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
576 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
579 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
582 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
585 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
588 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
591 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
594 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
597 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
600 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
603 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
608 return MM_ERROR_PLAYER_STREAMING_FAIL;
613 msg_param.data = (void *)(error->message);
616 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
618 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
619 msg_src_element, msg_param.code, (char *)msg_param.data);
622 /* post error to application */
623 if (!player->msg_posted) {
624 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
626 /* don't post more if one was sent already */
627 player->msg_posted = TRUE;
629 LOGD("skip error post because it's sent already.");
638 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
640 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
641 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
642 gst_tag_list_get_string(tags, "stitching_software",
643 &metadata->stitching_software);
644 gst_tag_list_get_string(tags, "projection_type",
645 &metadata->projection_type_string);
646 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
647 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
648 gst_tag_list_get_int(tags, "init_view_heading",
649 &metadata->init_view_heading);
650 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
651 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
652 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
653 gst_tag_list_get_int(tags, "full_pano_width_pixels",
654 &metadata->full_pano_width_pixels);
655 gst_tag_list_get_int(tags, "full_pano_height_pixels",
656 &metadata->full_pano_height_pixels);
657 gst_tag_list_get_int(tags, "cropped_area_image_width",
658 &metadata->cropped_area_image_width);
659 gst_tag_list_get_int(tags, "cropped_area_image_height",
660 &metadata->cropped_area_image_height);
661 gst_tag_list_get_int(tags, "cropped_area_left",
662 &metadata->cropped_area_left);
663 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
664 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
665 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
666 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
670 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
673 /* macro for better code readability */
674 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
676 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
677 if (string != NULL) { \
678 SECURE_LOGD("update tag string : %s", string); \
679 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
680 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
681 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
682 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
683 mm_player_set_attribute((MMHandleType)player, NULL,\
684 playertag, new_string, strlen(new_string), NULL); \
685 MMPLAYER_FREEIF(new_string); \
687 mm_player_set_attribute((MMHandleType)player, NULL,\
688 playertag, string, strlen(string), NULL); \
690 MMPLAYER_FREEIF(string); \
695 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
697 GstSample *sample = NULL;\
698 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
699 GstMapInfo info = GST_MAP_INFO_INIT;\
700 buffer = gst_sample_get_buffer(sample);\
701 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
702 LOGD("failed to get image data from tag");\
703 gst_sample_unref(sample);\
706 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
707 MMPLAYER_FREEIF(player->album_art);\
708 player->album_art = (gchar *)g_malloc(info.size);\
709 if (player->album_art) {\
710 memcpy(player->album_art, info.data, info.size);\
711 mm_player_set_attribute((MMHandleType)player, NULL,\
712 playertag, (void *)player->album_art, info.size, NULL); \
713 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
714 msg_param.data = (void *)player->album_art;\
715 msg_param.size = info.size;\
716 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
717 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
720 gst_buffer_unmap(buffer, &info);\
721 gst_sample_unref(sample);\
725 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
730 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
731 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
732 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
733 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
734 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
736 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
737 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
738 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
739 mm_player_set_attribute((MMHandleType)player, NULL,\
740 "content_audio_bitrate", v_uint, NULL); \
741 player->bitrate[track_type] = v_uint; \
742 player->total_bitrate = 0; \
743 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
744 player->total_bitrate += player->bitrate[i]; \
745 mm_player_set_attribute((MMHandleType)player, NULL,\
746 playertag, player->total_bitrate, NULL); \
747 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
748 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
749 player->maximum_bitrate[track_type] = v_uint; \
750 player->total_maximum_bitrate = 0; \
751 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
752 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, player->total_maximum_bitrate, NULL); \
755 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
757 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
764 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
766 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
768 string = g_strdup_printf("%d", g_date_get_year(date));\
769 mm_player_set_attribute((MMHandleType)player, NULL,\
770 playertag, string, strlen(string), NULL); \
771 SECURE_LOGD("metainfo year : %s", string);\
772 MMPLAYER_FREEIF(string);\
778 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
780 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
781 if (datetime != NULL) {\
782 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, string, strlen(string), NULL); \
785 SECURE_LOGD("metainfo year : %s", string);\
786 MMPLAYER_FREEIF(string);\
787 gst_date_time_unref(datetime);\
793 GstTagList *tag_list = NULL;
798 GstDateTime *datetime = NULL;
800 GstBuffer *buffer = NULL;
802 MMMessageParamType msg_param = {0, };
804 /* currently not used. but those are needed for above macro */
805 //guint64 v_uint64 = 0;
806 //gdouble v_double = 0;
808 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
810 /* get tag list from gst message */
811 gst_message_parse_tag(msg, &tag_list);
813 /* store tags to player attributes */
814 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
815 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
816 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
817 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
818 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
819 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
821 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
823 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
827 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
828 MMPLAYER_UPDATE_TAG_LOCK(player);
829 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
830 MMPLAYER_UPDATE_TAG_UNLOCK(player);
831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
833 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
834 if (player->video360_metadata.is_spherical == -1) {
835 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
836 mm_player_set_attribute((MMHandleType)player, NULL,
837 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
838 if (player->video360_metadata.is_spherical == 1) {
839 LOGD("This is spherical content for 360 playback.");
840 player->is_content_spherical = TRUE;
842 LOGD("This is not spherical content");
843 player->is_content_spherical = FALSE;
846 if (player->video360_metadata.projection_type_string) {
847 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
848 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
850 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
851 player->is_content_spherical = player->is_video360_enabled = FALSE;
855 if (player->video360_metadata.stereo_mode_string) {
856 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
857 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
858 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
859 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
860 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
861 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
863 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
864 player->is_content_spherical = player->is_video360_enabled = FALSE;
870 gst_tag_list_unref(tag_list);
876 static mmplayer_track_type_e
877 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
880 case GST_STREAM_TYPE_AUDIO:
881 return MM_PLAYER_TRACK_TYPE_AUDIO;
882 case GST_STREAM_TYPE_VIDEO:
883 return MM_PLAYER_TRACK_TYPE_VIDEO;
884 case GST_STREAM_TYPE_TEXT:
885 return MM_PLAYER_TRACK_TYPE_TEXT;
887 LOGD("not supported stream stype");
888 return MM_PLAYER_TRACK_TYPE_MAX;
892 /* if retval is FALSE, it will be dropped for performance. */
894 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
896 gboolean retval = FALSE;
898 if (!(player->pipeline && player->pipeline->mainbin)) {
899 LOGE("player pipeline handle is null");
903 switch (GST_MESSAGE_TYPE(message)) {
904 case GST_MESSAGE_TAG:
905 case GST_MESSAGE_EOS:
906 case GST_MESSAGE_ERROR:
907 case GST_MESSAGE_WARNING:
908 case GST_MESSAGE_CLOCK_LOST:
909 case GST_MESSAGE_NEW_CLOCK:
910 case GST_MESSAGE_ELEMENT:
911 case GST_MESSAGE_DURATION_CHANGED:
912 case GST_MESSAGE_ASYNC_START:
913 case GST_MESSAGE_STREAM_COLLECTION:
916 case GST_MESSAGE_ASYNC_DONE:
917 case GST_MESSAGE_STATE_CHANGED:
918 /* we only handle messages from pipeline */
919 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
924 case GST_MESSAGE_BUFFERING:
926 gint buffer_percent = 0;
929 gst_message_parse_buffering(message, &buffer_percent);
930 if (buffer_percent != MAX_BUFFER_PERCENT) {
931 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
935 if (!MMPLAYER_CMD_TRYLOCK(player)) {
936 LOGW("can't get cmd lock, send msg to bus");
940 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
941 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
942 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
945 MMPLAYER_CMD_UNLOCK(player);
949 case GST_MESSAGE_STREAMS_SELECTED:
951 if (MMPLAYER_USE_DECODEBIN(player))
952 break; /* drop msg */
954 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
955 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
956 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
958 gint64 dur_bytes = 0L;
960 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
961 LOGE("fail to get duration.");
963 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
964 * use file information was already set on Q2 when it was created. */
965 _mm_player_streaming_set_queue2(player->streamer,
966 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
967 TRUE, /* use_buffering */
968 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
969 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
972 LOGD("GST_MESSAGE_STREAMS_SELECTED");
973 player->no_more_pad = TRUE;
974 _mmplayer_set_reconfigure_state(player, FALSE);
975 if (!MMPLAYER_IS_ADAPTIVE_STREAMING(player))
976 _mmplayer_pipeline_complete(NULL, player);
989 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
991 guint64 data_size = 0;
994 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
996 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
998 if (MMPLAYER_IS_HTTP_STREAMING(player))
999 data_size = player->http_content_size;
1001 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1002 if (!player->streamer->is_adaptive_streaming) {
1003 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1007 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1008 if (!player->streamer->buffering_req.is_pre_buffering) {
1009 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1010 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1011 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1017 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1019 int ret = MM_ERROR_NONE;
1020 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1021 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1022 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1023 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1025 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1026 LOGW("do nothing for buffering msg");
1027 ret = MM_ERROR_PLAYER_INVALID_STATE;
1031 prev_state = MMPLAYER_PREV_STATE(player);
1032 current_state = MMPLAYER_CURRENT_STATE(player);
1033 target_state = MMPLAYER_TARGET_STATE(player);
1034 pending_state = MMPLAYER_PENDING_STATE(player);
1036 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1037 MMPLAYER_STATE_GET_NAME(prev_state),
1038 MMPLAYER_STATE_GET_NAME(current_state),
1039 MMPLAYER_STATE_GET_NAME(pending_state),
1040 MMPLAYER_STATE_GET_NAME(target_state),
1041 player->streamer->buffering_state);
1043 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1044 /* NOTE : if buffering has done, player has to go to target state. */
1045 switch (target_state) {
1046 case MM_PLAYER_STATE_PAUSED:
1048 switch (pending_state) {
1049 case MM_PLAYER_STATE_PLAYING:
1050 _mmplayer_gst_pause(player, TRUE);
1053 case MM_PLAYER_STATE_PAUSED:
1054 LOGD("player is already going to paused state, there is nothing to do.");
1057 case MM_PLAYER_STATE_NONE:
1058 case MM_PLAYER_STATE_NULL:
1059 case MM_PLAYER_STATE_READY:
1061 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1067 case MM_PLAYER_STATE_PLAYING:
1069 switch (pending_state) {
1070 case MM_PLAYER_STATE_NONE:
1072 if (current_state != MM_PLAYER_STATE_PLAYING)
1073 _mmplayer_gst_resume(player, TRUE);
1077 case MM_PLAYER_STATE_PAUSED:
1078 /* NOTE: It should be worked as asynchronously.
1079 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1081 if (current_state == MM_PLAYER_STATE_PLAYING) {
1082 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1083 * The current state should be changed to paused purposely to prevent state conflict.
1085 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1087 _mmplayer_gst_resume(player, TRUE);
1090 case MM_PLAYER_STATE_PLAYING:
1091 LOGD("player is already going to playing state, there is nothing to do.");
1094 case MM_PLAYER_STATE_NULL:
1095 case MM_PLAYER_STATE_READY:
1097 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1103 case MM_PLAYER_STATE_NULL:
1104 case MM_PLAYER_STATE_READY:
1105 case MM_PLAYER_STATE_NONE:
1107 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1111 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1112 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1114 switch (pending_state) {
1115 case MM_PLAYER_STATE_NONE:
1117 if (current_state != MM_PLAYER_STATE_PAUSED) {
1118 /* rtsp streaming pause makes rtsp server stop sending data. */
1119 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1120 LOGD("set pause state during buffering");
1121 _mmplayer_gst_pause(player, TRUE);
1127 case MM_PLAYER_STATE_PLAYING:
1128 /* rtsp streaming pause makes rtsp server stop sending data. */
1129 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1130 _mmplayer_gst_pause(player, TRUE);
1133 case MM_PLAYER_STATE_PAUSED:
1136 case MM_PLAYER_STATE_NULL:
1137 case MM_PLAYER_STATE_READY:
1139 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1148 static stream_variant_t *
1149 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1151 stream_variant_t *var_info = NULL;
1152 g_return_val_if_fail(self != NULL, NULL);
1154 var_info = g_new0(stream_variant_t, 1);
1155 if (!var_info) return NULL;
1156 var_info->bandwidth = self->bandwidth;
1157 var_info->width = self->width;
1158 var_info->height = self->height;
1163 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1169 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1170 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1172 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1173 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1174 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1176 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1177 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1178 player->http_content_size = (bytes > 0) ? bytes : 0;
1181 /* handling audio clip which has vbr. means duration is keep changing */
1182 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1191 __mmplayer_eos_timer_cb(gpointer u_data)
1193 mmplayer_t *player = NULL;
1194 MMHandleType attrs = 0;
1197 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1199 player = (mmplayer_t *)u_data;
1200 attrs = MMPLAYER_GET_ATTRS(player);
1202 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1206 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1207 if (ret_value != MM_ERROR_NONE)
1208 LOGE("seeking to 0 failed in repeat play");
1211 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1214 /* we are returning FALSE as we need only one posting */
1219 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1221 MMPLAYER_RETURN_IF_FAIL(player);
1223 /* post now if delay is zero */
1224 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1225 LOGD("eos delay is zero. posting EOS now");
1226 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1228 if (player->audio_decoded_cb)
1229 _mmplayer_cancel_eos_timer(player);
1234 /* cancel if existing */
1235 _mmplayer_cancel_eos_timer(player);
1237 /* init new timeout */
1238 /* NOTE : consider give high priority to this timer */
1239 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1241 player->eos_timer = g_timeout_add(delay_in_ms,
1242 __mmplayer_eos_timer_cb, player);
1244 player->context.global_default = g_main_context_default();
1245 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1247 /* check timer is valid. if not, send EOS now */
1248 if (player->eos_timer == 0) {
1249 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1250 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1255 __mmplayer_gst_pending_seek(mmplayer_t *player)
1257 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1258 int ret = MM_ERROR_NONE;
1262 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1264 if (!player->pending_seek.is_pending) {
1265 LOGD("pending seek is not reserved. nothing to do.");
1269 /* check player state if player could pending seek or not. */
1270 current_state = MMPLAYER_CURRENT_STATE(player);
1272 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1273 LOGW("try to pending seek in %s state, try next time. ",
1274 MMPLAYER_STATE_GET_NAME(current_state));
1278 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1280 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1281 if (ret != MM_ERROR_NONE)
1282 LOGE("failed to seek pending position. just keep staying current position.");
1284 player->pending_seek.is_pending = false;
1292 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1294 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1296 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1298 audiobin = player->pipeline->audiobin; /* can be null */
1299 videobin = player->pipeline->videobin; /* can be null */
1300 textbin = player->pipeline->textbin; /* can be null */
1302 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1304 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1305 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1307 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1308 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1310 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1311 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1317 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1319 mmplayer_gst_element_t *textbin;
1322 MMPLAYER_RETURN_IF_FAIL(player &&
1324 player->pipeline->textbin);
1326 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1328 textbin = player->pipeline->textbin;
1331 LOGD("Drop subtitle text after getting EOS");
1333 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1334 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1336 player->is_subtitle_force_drop = TRUE;
1338 if (player->is_subtitle_force_drop == TRUE) {
1339 LOGD("Enable subtitle data path without drop");
1341 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1342 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1344 LOGD("non-connected with external display");
1346 player->is_subtitle_force_drop = FALSE;
1352 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1354 MMHandleType attrs = 0;
1359 /* NOTE : EOS event is coming multiple time. watch out it */
1360 /* check state. we only process EOS when pipeline state goes to PLAYING */
1361 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1362 LOGD("EOS received on non-playing state. ignoring it");
1366 if (player->pipeline && player->pipeline->textbin)
1367 __mmplayer_drop_subtitle(player, TRUE);
1369 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1370 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1372 /* rewind if repeat count is greater then zero */
1373 /* get play count */
1374 attrs = MMPLAYER_GET_ATTRS(player);
1376 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1378 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1380 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1381 if (player->playback_rate < 0.0) {
1382 player->resumed_by_rewind = TRUE;
1383 _mmplayer_set_mute((MMHandleType)player, false);
1384 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1387 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1390 player->sent_bos = FALSE;
1392 LOGD("do not post eos msg for repeating");
1397 if (player->pipeline)
1398 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1400 /* post eos message to application */
1401 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1403 /* reset last position */
1404 player->last_position = 0;
1411 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1413 GError *error = NULL;
1414 gchar *debug = NULL;
1418 /* generating debug info before returning error */
1419 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1421 /* get error code */
1422 gst_message_parse_error(msg, &error, &debug);
1424 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1425 /* Note : the streaming error from the streaming source is handled
1426 * using __mmplayer_handle_streaming_error.
1428 __mmplayer_handle_streaming_error(player, msg, error);
1430 /* dump state of all element */
1431 _mmplayer_dump_pipeline_state(player);
1433 /* translate gst error code to msl error code. then post it
1434 * to application if needed
1436 __mmplayer_handle_gst_error(player, msg, error);
1439 LOGE("error debug : %s", debug);
1442 MMPLAYER_FREEIF(debug);
1443 g_error_free(error);
1450 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1452 MMMessageParamType msg_param = {0, };
1453 int bRet = MM_ERROR_NONE;
1456 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1458 if (!MMPLAYER_IS_STREAMING(player)) {
1459 LOGW("this is not streaming playback.");
1463 MMPLAYER_CMD_LOCK(player);
1465 if (!player->streamer) {
1466 LOGW("Pipeline is shutting down");
1467 MMPLAYER_CMD_UNLOCK(player);
1471 /* ignore the remained buffering message till getting 100% msg */
1472 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1473 gint buffer_percent = 0;
1475 gst_message_parse_buffering(msg, &buffer_percent);
1477 if (buffer_percent == MAX_BUFFER_PERCENT) {
1478 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1479 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1480 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1482 MMPLAYER_CMD_UNLOCK(player);
1486 /* ignore the remained buffering message */
1487 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1488 gint buffer_percent = 0;
1490 gst_message_parse_buffering(msg, &buffer_percent);
1492 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1493 player->streamer->buffering_percent, buffer_percent);
1495 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1496 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1497 player->streamer->buffering_req.is_pre_buffering = FALSE;
1499 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1501 LOGD("interrupted buffering - ignored the remained buffering msg!");
1502 MMPLAYER_CMD_UNLOCK(player);
1507 __mmplayer_update_buffer_setting(player, msg);
1509 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1511 if (bRet == MM_ERROR_NONE) {
1512 msg_param.connection.buffering = player->streamer->buffering_percent;
1513 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1515 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1516 player->pending_resume &&
1517 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1519 player->is_external_subtitle_added_now = FALSE;
1520 player->pending_resume = FALSE;
1521 _mmplayer_resume((MMHandleType)player);
1524 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1525 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1528 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1529 player->seek_state = MMPLAYER_SEEK_NONE;
1530 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1531 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1532 /* Considering the async state transition in case of RTSP.
1533 After getting state change gst msg, seek completed msg will be posted. */
1534 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1538 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1539 if (!player->streamer) {
1540 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1541 MMPLAYER_CMD_UNLOCK(player);
1545 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1547 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1548 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1550 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1551 msg_param.connection.buffering = player->streamer->buffering_percent;
1552 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1554 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1557 msg_param.connection.buffering = player->streamer->buffering_percent;
1558 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1561 MMPLAYER_CMD_UNLOCK(player);
1569 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1571 mmplayer_gst_element_t *mainbin;
1572 GstState oldstate = GST_STATE_NULL;
1573 GstState newstate = GST_STATE_NULL;
1574 GstState pending = GST_STATE_NULL;
1577 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1579 mainbin = player->pipeline->mainbin;
1581 /* we only handle messages from pipeline */
1582 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1585 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pending);
1587 LOGD("state changed [%s] : %s ---> %s final : %s",
1588 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1589 gst_element_state_get_name((GstState)oldstate),
1590 gst_element_state_get_name((GstState)newstate),
1591 gst_element_state_get_name((GstState)pending));
1593 if (newstate == GST_STATE_PLAYING) {
1594 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1596 int retVal = MM_ERROR_NONE;
1597 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1599 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1601 if (MM_ERROR_NONE != retVal)
1602 LOGE("failed to seek pending position. just keep staying current position.");
1604 player->pending_seek.is_pending = false;
1608 if (oldstate == newstate) {
1609 LOGD("pipeline reports state transition to old state");
1614 case GST_STATE_PAUSED:
1616 gboolean prepare_async = FALSE;
1618 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1619 // managed prepare async case
1620 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1621 LOGD("checking prepare mode for async transition - %d", prepare_async);
1624 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1625 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1627 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1628 _mm_player_streaming_set_content_bitrate(player->streamer,
1629 player->total_maximum_bitrate, player->total_bitrate);
1631 if (player->pending_seek.is_pending) {
1632 LOGW("trying to do pending seek");
1633 MMPLAYER_CMD_LOCK(player);
1634 __mmplayer_gst_pending_seek(player);
1635 MMPLAYER_CMD_UNLOCK(player);
1641 case GST_STATE_PLAYING:
1643 if (MMPLAYER_IS_STREAMING(player)) {
1644 // managed prepare async case when buffering is completed
1645 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1646 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1647 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1648 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1650 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1652 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1653 if (player->streamer->buffering_percent < 100) {
1655 MMMessageParamType msg_param = {0, };
1656 LOGW("Posting Buffering Completed Message to Application !!!");
1658 msg_param.connection.buffering = 100;
1659 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1664 if (player->gapless.stream_changed) {
1665 _mmplayer_update_content_attrs(player, ATTR_ALL);
1666 player->gapless.stream_changed = FALSE;
1669 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1670 player->seek_state = MMPLAYER_SEEK_NONE;
1671 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1675 case GST_STATE_VOID_PENDING:
1676 case GST_STATE_NULL:
1677 case GST_STATE_READY:
1687 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1689 const gchar *structure_name;
1690 gint count = 0, idx = 0;
1693 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1695 if (gst_message_get_structure(msg) == NULL)
1698 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1699 if (!structure_name)
1702 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1704 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1705 const GValue *var_info = NULL;
1707 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1708 if (var_info != NULL) {
1709 if (player->adaptive_info.var_list)
1710 g_list_free_full(player->adaptive_info.var_list, g_free);
1712 /* share addr or copy the list */
1713 player->adaptive_info.var_list =
1714 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1716 count = g_list_length(player->adaptive_info.var_list);
1718 stream_variant_t *temp = NULL;
1720 /* print out for debug */
1721 LOGD("num of variant_info %d", count);
1722 for (idx = 0; idx < count; idx++) {
1723 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1725 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1731 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1732 gint num_buffers = 0;
1733 gint extra_num_buffers = 0;
1735 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1736 LOGD("video_num_buffers : %d", num_buffers);
1737 mm_player_set_attribute((MMHandleType)player, NULL,
1738 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1741 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1742 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1743 mm_player_set_attribute((MMHandleType)player, NULL,
1744 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1749 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1750 _mmplayer_track_update_text_attr_info(player, msg);
1752 /* custom message */
1753 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1754 MMMessageParamType msg_param = {0,};
1755 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1756 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1759 /* custom message for RTSP attribute :
1760 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1761 sdp which has contents info is received when rtsp connection is opened.
1762 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1763 if (!strcmp(structure_name, "rtspsrc_properties")) {
1764 g_autofree gchar *audio_codec = NULL;
1765 g_autofree gchar *video_codec = NULL;
1766 g_autofree gchar *video_frame_size = NULL;
1768 gst_structure_get(gst_message_get_structure(msg),
1769 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1770 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1771 player->streaming_type = _mmplayer_get_stream_service_type(player);
1773 gst_structure_get(gst_message_get_structure(msg),
1774 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1775 LOGD("rtsp_audio_codec : %s", audio_codec);
1777 mm_player_set_attribute((MMHandleType)player, NULL,
1778 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1780 gst_structure_get(gst_message_get_structure(msg),
1781 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1782 LOGD("rtsp_video_codec : %s", video_codec);
1784 mm_player_set_attribute((MMHandleType)player, NULL,
1785 "content_video_codec", video_codec, strlen(video_codec), NULL);
1787 gst_structure_get(gst_message_get_structure(msg),
1788 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1789 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1790 if (video_frame_size) {
1791 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1792 mm_player_set_attribute((MMHandleType)player, NULL,
1793 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1794 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1796 g_strfreev(res_str);
1805 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1807 mmplayer_gst_element_t *mainbin;
1810 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1812 mainbin = player->pipeline->mainbin;
1814 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1816 /* we only handle messages from pipeline */
1817 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1820 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1821 if (player->is_external_subtitle_present)
1822 _mmplayer_sync_subtitle_pipeline(player);
1824 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1825 player->seek_state = MMPLAYER_SEEK_NONE;
1826 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1827 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1828 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1829 LOGD("sync %s state(%s) with parent state(%s)",
1830 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1831 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1832 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1834 /* In case of streaming, pause is required before finishing seeking by buffering.
1835 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1836 Because the buffering state is controlled according to the state transition for force resume,
1837 the decodebin state should be paused as player state. */
1838 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1841 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1842 (player->streamer) &&
1843 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1844 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1845 GstQuery *query = NULL;
1846 gboolean busy = FALSE;
1849 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1850 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1851 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1852 gst_query_parse_buffering_percent(query, &busy, &percent);
1853 gst_query_unref(query);
1855 LOGD("buffered percent(%s): %d",
1856 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1860 __mmplayer_handle_buffering_playback(player);
1863 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1873 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1875 GValue val = { 0, };
1877 guint indent = GPOINTER_TO_UINT(user_data);
1879 if (!gst_tag_list_copy_value(&val, tags, tag))
1882 if (G_VALUE_HOLDS_STRING(&val))
1883 str = g_value_dup_string(&val);
1885 str = gst_value_serialize(&val);
1887 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1889 g_value_unset(&val);
1894 __mmplayer_dump_collection(GstStreamCollection * collection)
1898 GstTagList *tags = NULL;
1900 GstCaps *caps = NULL;
1902 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1903 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1904 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1905 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1906 gst_stream_get_stream_flags(stream));
1907 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1909 caps = gst_stream_get_caps(stream);
1911 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1912 gst_caps_unref(caps);
1916 tags = gst_stream_get_tags(stream);
1919 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1920 gst_tag_list_unref(tags);
1927 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1928 GstStream *stream, GParamSpec *pspec, gpointer data)
1930 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1931 gst_stream_get_stream_id(stream), pspec->name, collection);
1932 if (g_str_equal(pspec->name, "caps")) {
1933 GstCaps *caps = gst_stream_get_caps(stream);
1934 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1935 gst_caps_unref(caps);
1939 if (g_str_equal (pspec->name, "tags")) {
1940 GstTagList *tags = gst_stream_get_tags(stream);
1943 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1944 gst_tag_list_unref(tags);
1951 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1953 mmplayer_t *player = (mmplayer_t *)(data);
1955 MMPLAYER_RETURN_IF_FAIL(player);
1956 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1958 switch (GST_MESSAGE_TYPE(msg)) {
1959 case GST_MESSAGE_UNKNOWN:
1960 LOGD("unknown message received");
1963 case GST_MESSAGE_EOS:
1964 LOGD("GST_MESSAGE_EOS received");
1965 __mmplayer_gst_handle_eos_message(player, msg);
1968 case GST_MESSAGE_ERROR:
1969 _mmplayer_set_reconfigure_state(player, FALSE);
1970 __mmplayer_gst_handle_error_message(player, msg);
1973 case GST_MESSAGE_WARNING:
1976 GError *error = NULL;
1978 gst_message_parse_warning(msg, &error, &debug);
1980 LOGD("warning : %s", error->message);
1981 LOGD("debug : %s", debug);
1983 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1985 MMPLAYER_FREEIF(debug);
1986 g_error_free(error);
1990 case GST_MESSAGE_TAG:
1992 LOGD("GST_MESSAGE_TAG");
1993 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1994 LOGW("failed to extract tags from gstmessage");
1998 case GST_MESSAGE_BUFFERING:
1999 __mmplayer_gst_handle_buffering_message(player, msg);
2002 case GST_MESSAGE_STATE_CHANGED:
2003 __mmplayer_gst_handle_state_message(player, msg);
2006 case GST_MESSAGE_CLOCK_LOST:
2008 GstClock *clock = NULL;
2009 gboolean need_new_clock = FALSE;
2011 gst_message_parse_clock_lost(msg, &clock);
2012 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2014 if (!player->videodec_linked)
2015 need_new_clock = TRUE;
2016 else if (!player->ini.use_system_clock)
2017 need_new_clock = TRUE;
2019 if (need_new_clock) {
2020 LOGD("Provide clock is TRUE, do pause->resume");
2021 _mmplayer_gst_pause(player, FALSE);
2022 _mmplayer_gst_resume(player, FALSE);
2027 case GST_MESSAGE_NEW_CLOCK:
2029 GstClock *clock = NULL;
2030 gst_message_parse_new_clock(msg, &clock);
2031 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2035 case GST_MESSAGE_ELEMENT:
2036 __mmplayer_gst_handle_element_message(player, msg);
2039 case GST_MESSAGE_DURATION_CHANGED:
2041 LOGD("GST_MESSAGE_DURATION_CHANGED");
2042 if (!__mmplayer_gst_handle_duration(player, msg))
2043 LOGW("failed to update duration");
2047 case GST_MESSAGE_ASYNC_START:
2048 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2051 case GST_MESSAGE_ASYNC_DONE:
2052 __mmplayer_gst_handle_async_done_message(player, msg);
2054 case GST_MESSAGE_STREAM_COLLECTION:
2056 GstStreamCollection *collection = NULL;
2057 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2059 gst_message_parse_stream_collection(msg, &collection);
2061 __mmplayer_dump_collection(collection);
2062 if (player->collection && player->stream_notify_id) {
2063 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2064 player->stream_notify_id = 0;
2066 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2067 if (player->collection) {
2068 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2069 (GCallback)__mmplayer_stream_notify_cb, player);
2071 gst_object_unref(collection);
2074 case GST_MESSAGE_STREAMS_SELECTED:
2076 GstStreamCollection *collection = NULL;
2077 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2079 gst_message_parse_streams_selected(msg, &collection);
2081 guint len = gst_message_streams_selected_get_size(msg);
2082 for (guint i = 0; i < len; i++) {
2083 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2084 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2085 gst_stream_get_stream_type(stream));
2086 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2087 LOGD("not supported track type");
2088 gst_object_unref(stream);
2091 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2092 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2093 int stream_index = INVALID_TRACK_INDEX;
2094 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2095 player->track[type].active_track_index = stream_index;
2096 LOGD("selected this stream, update active idx : %d",
2097 player->track[type].active_track_index);
2100 gst_object_unref(stream);
2102 gst_object_unref(collection);
2107 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2108 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2109 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2110 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2111 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2112 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2113 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2114 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2115 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2116 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2117 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2118 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2119 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2120 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2121 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2128 /* should not call 'gst_message_unref(msg)' */
2132 static GstBusSyncReply
2133 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2135 mmplayer_t *player = (mmplayer_t *)data;
2136 GstBusSyncReply reply = GST_BUS_DROP;
2138 if (!(player->pipeline && player->pipeline->mainbin)) {
2139 LOGE("player pipeline handle is null");
2140 return GST_BUS_PASS;
2143 if (!__mmplayer_gst_check_useful_message(player, message)) {
2144 gst_message_unref(message);
2145 return GST_BUS_DROP;
2148 switch (GST_MESSAGE_TYPE(message)) {
2149 case GST_MESSAGE_TAG:
2150 __mmplayer_gst_extract_tag_from_msg(player, message);
2154 GstTagList *tags = NULL;
2156 gst_message_parse_tag(message, &tags);
2158 LOGE("TAGS received from element \"%s\".",
2159 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2161 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2162 gst_tag_list_unref(tags);
2170 case GST_MESSAGE_DURATION_CHANGED:
2171 __mmplayer_gst_handle_duration(player, message);
2173 case GST_MESSAGE_ELEMENT:
2175 const gchar *klass = NULL;
2176 klass = gst_element_factory_get_metadata
2177 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2178 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2179 reply = GST_BUS_PASS;
2182 __mmplayer_gst_handle_element_message(player, message);
2185 case GST_MESSAGE_ASYNC_DONE:
2186 /* NOTE:Don't call gst_callback directly
2187 * because previous frame can be showed even though this message is received for seek.
2190 reply = GST_BUS_PASS;
2194 if (reply == GST_BUS_DROP)
2195 gst_message_unref(message);
2201 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2203 GstElement *appsrc = element;
2204 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2205 GstBuffer *buffer = NULL;
2206 GstFlowReturn ret = GST_FLOW_OK;
2209 MMPLAYER_RETURN_IF_FAIL(element);
2210 MMPLAYER_RETURN_IF_FAIL(buf);
2212 buffer = gst_buffer_new();
2214 if (buf->offset < 0 || buf->len < 0) {
2215 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2219 if (buf->offset >= buf->len) {
2220 LOGD("call eos appsrc");
2221 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2225 if (buf->len - buf->offset < size)
2226 len = buf->len - buf->offset;
2228 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2229 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2230 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2233 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2235 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2241 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2243 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2245 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2247 buf->offset = (int)size;
2253 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2255 mmplayer_t *player = (mmplayer_t *)user_data;
2256 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2257 MMMessageParamType msg_param = {0,};
2258 guint64 current_level_bytes = 0;
2260 MMPLAYER_RETURN_IF_FAIL(player);
2262 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2263 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2264 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2265 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2267 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2271 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2273 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2275 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2276 msg_param.buffer_status.stream_type = stream_type;
2277 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2278 msg_param.buffer_status.bytes = current_level_bytes;
2280 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2284 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2286 mmplayer_t *player = (mmplayer_t *)user_data;
2287 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2288 MMMessageParamType msg_param = {0,};
2289 guint64 current_level_bytes = 0;
2291 MMPLAYER_RETURN_IF_FAIL(player);
2293 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2294 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2295 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2296 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2298 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2302 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2304 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2306 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2307 msg_param.buffer_status.stream_type = stream_type;
2308 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2309 msg_param.buffer_status.bytes = current_level_bytes;
2311 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2315 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2317 mmplayer_t *player = (mmplayer_t *)user_data;
2318 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2319 MMMessageParamType msg_param = {0,};
2321 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2323 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2324 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2325 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2326 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2328 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2332 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2334 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2335 msg_param.seek_data.stream_type = stream_type;
2336 msg_param.seek_data.offset = position;
2338 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2344 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2346 #define MAX_LEN_NAME 20
2348 gboolean ret = FALSE;
2349 GstPad *sinkpad = NULL;
2350 gchar *prefix = NULL;
2351 gchar dec_name[MAX_LEN_NAME] = {0, };
2352 main_element_id_e elem_id = MMPLAYER_M_NUM;
2354 mmplayer_gst_element_t *mainbin = NULL;
2355 GstElement *decodebin = NULL;
2356 GstCaps *dec_caps = NULL;
2360 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2362 player->pipeline->mainbin, FALSE);
2363 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2365 mainbin = player->pipeline->mainbin;
2367 case MM_PLAYER_STREAM_TYPE_AUDIO:
2369 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2371 case MM_PLAYER_STREAM_TYPE_VIDEO:
2373 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2376 LOGE("invalid type %d", type);
2380 if (mainbin[elem_id].gst) {
2381 LOGE("elem(%d) is already created", elem_id);
2385 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2387 /* create decodebin */
2388 decodebin = gst_element_factory_make("decodebin", dec_name);
2390 LOGE("failed to create %s", dec_name);
2394 /* raw pad handling signal */
2395 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2396 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2398 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2399 before looking for any elements that can handle that stream.*/
2400 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2401 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2403 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2404 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2405 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2407 /* This signal is emitted when a element is added to the bin.*/
2408 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2409 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2411 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2412 LOGE("failed to add new decodebin");
2416 dec_caps = gst_pad_query_caps(srcpad, NULL);
2419 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2421 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2422 gst_caps_unref(dec_caps);
2425 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2427 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2428 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2431 gst_object_unref(GST_OBJECT(sinkpad));
2433 gst_element_sync_state_with_parent(decodebin);
2435 mainbin[elem_id].id = elem_id;
2436 mainbin[elem_id].gst = decodebin;
2443 gst_object_unref(GST_OBJECT(sinkpad));
2446 gst_element_set_state(decodebin, GST_STATE_NULL);
2447 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2448 gst_object_unref(decodebin);
2456 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2458 #define MAX_LEN_NAME 20
2459 mmplayer_gst_element_t *mainbin = NULL;
2460 gchar *prefix = NULL;
2461 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2463 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2464 GstElement *src = NULL, *queue = NULL;
2465 GstPad *srcpad = NULL;
2468 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2469 player->pipeline->mainbin, FALSE);
2471 mainbin = player->pipeline->mainbin;
2473 LOGD("type(%d) path is creating", type);
2475 case MM_PLAYER_STREAM_TYPE_AUDIO:
2477 if (mainbin[MMPLAYER_M_SRC].gst)
2478 src_id = MMPLAYER_M_2ND_SRC;
2480 src_id = MMPLAYER_M_SRC;
2481 queue_id = MMPLAYER_M_A_BUFFER;
2483 case MM_PLAYER_STREAM_TYPE_VIDEO:
2485 src_id = MMPLAYER_M_SRC;
2486 queue_id = MMPLAYER_M_V_BUFFER;
2488 case MM_PLAYER_STREAM_TYPE_TEXT:
2489 prefix = "subtitle";
2490 src_id = MMPLAYER_M_SUBSRC;
2491 queue_id = MMPLAYER_M_S_BUFFER;
2494 LOGE("invalid type %d", type);
2498 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2499 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2502 src = gst_element_factory_make("appsrc", src_name);
2504 LOGF("failed to create %s", src_name);
2508 mainbin[src_id].id = src_id;
2509 mainbin[src_id].gst = src;
2511 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2512 "caps", caps, NULL);
2514 /* size of many video frames are larger than default blocksize as 4096 */
2515 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2516 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2518 if (player->media_stream_buffer_max_size[type] > 0)
2519 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2521 if (player->media_stream_buffer_min_percent[type] > 0)
2522 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2524 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2525 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2527 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2528 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2529 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2530 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2531 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2532 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2535 queue = gst_element_factory_make("queue2", queue_name);
2537 LOGE("failed to create %s", queue_name);
2540 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2542 mainbin[queue_id].id = queue_id;
2543 mainbin[queue_id].gst = queue;
2545 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2546 LOGE("failed to add src");
2550 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2551 LOGE("failed to add queue");
2555 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2556 LOGE("failed to link src and queue");
2560 /* create decoder */
2561 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2563 LOGE("failed to get srcpad of queue");
2567 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2568 _mmplayer_gst_create_decoder(player, srcpad, caps);
2570 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2571 LOGE("failed to create decoder");
2572 gst_object_unref(GST_OBJECT(srcpad));
2576 gst_object_unref(GST_OBJECT(srcpad));
2580 if (mainbin[src_id].gst) {
2581 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2582 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2583 gst_object_unref(mainbin[src_id].gst);
2584 mainbin[src_id].gst = NULL;
2587 if (mainbin[queue_id].gst) {
2588 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2589 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2590 gst_object_unref(mainbin[queue_id].gst);
2591 mainbin[queue_id].gst = NULL;
2598 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2600 GstPad *sinkpad = NULL;
2601 GstCaps *caps = NULL;
2602 GstElement *new_element = NULL;
2603 GstStructure *str = NULL;
2604 const gchar *name = NULL;
2606 mmplayer_t *player = (mmplayer_t *)data;
2610 MMPLAYER_RETURN_IF_FAIL(element && pad);
2611 MMPLAYER_RETURN_IF_FAIL(player &&
2613 player->pipeline->mainbin);
2615 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2616 * num_dynamic_pad will decreased after creating a sinkbin.
2618 player->num_dynamic_pad++;
2619 LOGD("stream count inc : %d", player->num_dynamic_pad);
2621 caps = gst_pad_query_caps(pad, NULL);
2622 MMPLAYER_CHECK_NULL(caps);
2624 str = gst_caps_get_structure(caps, 0);
2625 name = gst_structure_get_string(str, "media");
2627 LOGE("cannot get mimetype from structure.");
2631 if (strstr(name, "video")) {
2633 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2635 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2636 if (player->v_stream_caps) {
2637 gst_caps_unref(player->v_stream_caps);
2638 player->v_stream_caps = NULL;
2641 new_element = gst_element_factory_make("fakesink", NULL);
2642 player->num_dynamic_pad--;
2647 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2648 LOGE("failed to autoplug for caps");
2652 gst_caps_unref(caps);
2657 /* execute new_element if created*/
2659 LOGD("adding new element to pipeline");
2661 /* set state to READY before add to bin */
2662 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2664 /* add new element to the pipeline */
2665 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2666 LOGE("failed to add autoplug element to bin");
2670 /* get pad from element */
2671 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2673 LOGE("failed to get sinkpad from autoplug element");
2678 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2679 LOGE("failed to link autoplug element");
2683 gst_object_unref(sinkpad);
2686 /* run. setting PLAYING here since streaming source is live source */
2687 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2691 gst_caps_unref(caps);
2697 STATE_CHANGE_FAILED:
2699 /* FIXIT : take care if new_element has already added to pipeline */
2701 gst_object_unref(GST_OBJECT(new_element));
2704 gst_object_unref(GST_OBJECT(sinkpad));
2707 gst_caps_unref(caps);
2709 /* FIXIT : how to inform this error to MSL ????? */
2710 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2711 * then post an error to application
2716 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2718 mmplayer_t *player = (mmplayer_t *)data;
2722 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2723 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2724 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2725 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2727 * [1] audio and video will be dumped with filesink.
2728 * [2] autoplugging is done by just using pad caps.
2729 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2730 * and the video will be dumped via filesink.
2732 if (player->num_dynamic_pad == 0) {
2733 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2735 if (!_mmplayer_gst_remove_fakesink(player,
2736 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2737 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2738 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2739 * source element are not same. To overcome this situation, this function will called
2740 * several places and several times. Therefore, this is not an error case.
2745 /* create dot before error-return. for debugging */
2746 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2748 player->no_more_pad = TRUE;
2754 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2756 GstElement *element = NULL;
2757 gchar *user_agent = NULL;
2758 MMHandleType attrs = 0;
2761 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2763 /* get profile attribute */
2764 attrs = MMPLAYER_GET_ATTRS(player);
2766 LOGE("failed to get content attribute");
2770 element = gst_element_factory_make("rtspsrc", "rtsp source");
2772 LOGE("failed to create rtspsrc element");
2777 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2779 SECURE_LOGD("user_agent : %s", user_agent);
2781 /* setting property to streaming source */
2782 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2784 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2786 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2787 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2788 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2789 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2795 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2797 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2799 mmplayer_t *player = (mmplayer_t *)data;
2800 MMHandleType attrs = 0;
2801 gchar *user_agent, *cookies, **cookie_list;
2802 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2803 user_agent = cookies = NULL;
2807 MMPLAYER_RETURN_IF_FAIL(player);
2809 LOGD("source element %s", GST_ELEMENT_NAME(source));
2811 attrs = MMPLAYER_GET_ATTRS(player);
2813 LOGE("failed to get content attribute");
2817 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2818 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2820 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2821 http_timeout = player->ini.http_timeout;
2823 SECURE_LOGD("cookies : %s", cookies);
2824 SECURE_LOGD("user_agent : %s", user_agent);
2825 LOGD("timeout : %d", http_timeout);
2827 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2829 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2830 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2831 g_strfreev(cookie_list);
2835 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2841 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2843 mmplayer_t *player = (mmplayer_t *)data;
2844 gchar *user_agent = NULL;
2845 MMHandleType attrs = 0;
2848 MMPLAYER_RETURN_IF_FAIL(player);
2850 attrs = MMPLAYER_GET_ATTRS(player);
2852 LOGE("failed to get content attribute");
2856 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2858 SECURE_LOGD("user_agent : %s", user_agent);
2861 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2867 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2869 mmplayer_t *player = (mmplayer_t *)data;
2870 GstElement *source = NULL;
2873 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2875 g_object_get(orig, pspec->name, &source, NULL);
2877 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2878 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2880 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2881 __mmplayer_http_src_setup(source, data);
2882 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2883 __mmplayer_rtsp_src_setup(source, data);
2884 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2885 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2886 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2887 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2888 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2890 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2891 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2892 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2893 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2895 gst_object_unref (source);
2901 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2902 GstStream * stream, gpointer data)
2904 #define RET_SELECT 1
2906 #define RET_DEPENDS_ON_DECODEBIN -1
2908 GstStreamType stype = gst_stream_get_stream_type(stream);
2909 mmplayer_t *player = (mmplayer_t *)data;
2910 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2911 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2912 g_autofree gchar *caps_str = NULL;
2913 GstStructure *caps_structure = NULL;
2914 int stream_index = INVALID_TRACK_INDEX;
2915 int ret = MM_ERROR_NONE;
2917 LOGD("Stream type %s flags 0x%x",
2918 gst_stream_type_get_name(stype),
2919 gst_stream_get_stream_flags(stream));
2920 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2922 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
2925 caps_str = gst_caps_to_string(caps);
2926 caps_structure = gst_caps_get_structure(caps, 0);
2927 const gchar *mime = gst_structure_get_name(caps_structure);
2929 LOGD(" caps: %s", caps_str);
2931 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2932 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2933 LOGW("skip [%s] by unsupported codec keyword [%s]",
2934 mime, player->ini.unsupported_codec_keyword[idx]);
2936 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2940 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2941 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2942 LOGD("No caps info, depends on decodebin");
2943 _mmplayer_track_update_stream(player, type, stream);
2944 return RET_DEPENDS_ON_DECODEBIN;
2947 LOGD("No caps info, skip it");
2952 case GST_STREAM_TYPE_AUDIO:
2954 if (caps_structure) {
2955 gint samplerate = 0;
2958 gst_structure_get_int(caps_structure, "rate", &samplerate);
2959 gst_structure_get_int(caps_structure, "channels", &channels);
2960 if (samplerate == 0 && channels > 0) {
2961 LOGW("Skip corrupted audio stream");
2965 if (g_strrstr(caps_str, "mobile-xmf"))
2966 mm_player_set_attribute((MMHandleType)player, NULL,
2967 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2971 case GST_STREAM_TYPE_VIDEO:
2973 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2974 LOGD("do not support muti track video");
2978 // FIXME: it cause block during preparing
2979 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2982 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2983 /* don't make video because of not required */
2984 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2985 (!player->set_mode.video_export)) {
2986 LOGD("no need video decoding, skip video stream");
2991 if (caps_structure) {
2994 gst_structure_get_int(caps_structure, "width", &width);
2996 if (player->v_stream_caps) {
2997 gst_caps_unref(player->v_stream_caps);
2998 player->v_stream_caps = NULL;
3001 player->v_stream_caps = gst_caps_copy(caps);
3002 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3007 case GST_STREAM_TYPE_TEXT:
3010 LOGW("Skip not supported stream type");
3014 _mmplayer_track_update_stream(player, type, stream);
3016 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3018 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3019 (ret == MM_ERROR_NONE)) {
3020 player->track[type].active_track_index = stream_index;
3021 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3022 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3023 _mmplayer_set_audio_attrs(player, caps);
3027 if (player->track[type].active_track_index == stream_index) {
3028 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3032 LOGD("Skip stream");
3037 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3038 GstStream * stream, gpointer data)
3040 mmplayer_t *player = (mmplayer_t *)data;
3041 GstStreamType stype = gst_stream_get_stream_type(stream);
3044 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3046 LOGD("stream type %s", gst_stream_type_get_name(stype));
3048 /* public does not support audio hw decoder at the moment */
3050 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3051 LOGW("video decoder resource is already acquired, skip it.");
3055 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3056 LOGE("failed to acquire video decoder resource");
3059 player->interrupted_by_resource = FALSE;
3065 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3067 GstIterator *iter = NULL;
3068 GValue item = {0, };
3069 GstElement *ch_element = NULL;
3070 GstElementFactory *ch_factory = NULL;
3073 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3075 iter = gst_bin_iterate_recurse(bin);
3076 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3078 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3079 ch_element = g_value_get_object(&item);
3080 ch_factory = gst_element_get_factory(ch_element);
3081 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3082 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3083 LOGD("Find %s element", element_name);
3087 g_value_reset(&item);
3089 gst_iterator_free(iter);
3095 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3097 mmplayer_t *player = (mmplayer_t *)data;
3099 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3101 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3102 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3103 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3105 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3106 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3107 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3110 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3112 mmplayer_t *player = (mmplayer_t *)data;
3113 int video_codec_type = 0;
3114 int audio_codec_type = 0;
3116 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3118 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3119 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3121 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3123 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3124 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3125 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3126 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3128 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3129 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3133 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3135 gchar *factory_name = NULL;
3136 mmplayer_t *player = (mmplayer_t *)data;
3139 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3141 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3143 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3145 if (g_strrstr(factory_name, "urisourcebin")) {
3146 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3148 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3150 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3152 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3154 LOGW("failed to find decodebin3");
3156 } else if (g_strrstr(factory_name, "parsebin")) {
3157 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3158 __mmplayer_parsebin_setup(GST_BIN(element), data);
3160 _mmplayer_gst_element_added(child, element, data);
3165 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3169 MMPLAYER_RETURN_IF_FAIL(player);
3170 MMPLAYER_RETURN_IF_FAIL(removed_element);
3172 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3174 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3175 GList *node = player->signals[type];
3177 GList *next_node = node->next;
3178 mmplayer_signal_item_t *item = node->data;
3179 if (item && item->obj == G_OBJECT(removed_element)) {
3180 player->signals[type] = g_list_delete_link(player->signals[type], node);
3181 MMPLAYER_FREEIF(item);
3191 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3193 mmplayer_t *player = (mmplayer_t *)data;
3197 MMPLAYER_RETURN_IF_FAIL(player);
3199 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3201 __mmplayer_delete_signal_connection(player, element);
3207 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3209 GstElement *uridecodebin3 = NULL;
3212 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3214 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3215 if (!uridecodebin3) {
3216 LOGE("failed to create uridecodebin3");
3221 SECURE_LOGD("uri : %s", player->profile.uri);
3223 /* setting property to streaming source */
3224 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3225 "message-forward", TRUE,
3226 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3227 "use-buffering", TRUE, NULL);
3229 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3230 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3232 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3233 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3235 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3236 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3238 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3239 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3241 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3242 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3244 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3245 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3247 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3248 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3250 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3251 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3253 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3254 LOGW("[DASH] this is still experimental feature");
3257 return uridecodebin3;
3261 __mmplayer_gst_make_http_src(mmplayer_t *player)
3263 #define MAX_RETRY_COUNT 10
3264 GstElement *element = NULL;
3265 MMHandleType attrs = 0;
3266 gchar *user_agent, *cookies, **cookie_list;
3267 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3269 user_agent = cookies = NULL;
3273 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3275 /* get profile attribute */
3276 attrs = MMPLAYER_GET_ATTRS(player);
3278 LOGE("failed to get content attribute");
3282 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3284 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3286 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3291 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3292 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3294 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3295 http_timeout = player->ini.http_timeout;
3298 SECURE_LOGD("location : %s", player->profile.uri);
3299 SECURE_LOGD("cookies : %s", cookies);
3300 SECURE_LOGD("user_agent : %s", user_agent);
3301 LOGD("timeout : %d", http_timeout);
3303 /* setting property to streaming source */
3304 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3305 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3306 "retries", MAX_RETRY_COUNT, NULL);
3308 /* parsing cookies */
3309 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3310 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3311 g_strfreev(cookie_list);
3315 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3317 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3318 LOGW("[DASH] this is still experimental feature");
3325 __mmplayer_gst_make_file_src(mmplayer_t *player)
3327 GstElement *element = NULL;
3330 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3332 LOGD("using filesrc for 'file://' handler");
3333 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3334 LOGE("failed to get storage info");
3338 element = gst_element_factory_make("filesrc", "source");
3340 LOGE("failed to create filesrc");
3344 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3351 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3353 mmplayer_t *player = (mmplayer_t *)data;
3355 g_return_val_if_fail(player, FALSE);
3356 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3357 gst_message_ref(msg);
3359 g_mutex_lock(&player->bus_msg_q_lock);
3360 g_queue_push_tail(player->bus_msg_q, msg);
3361 g_mutex_unlock(&player->bus_msg_q_lock);
3363 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3364 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3365 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3369 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3371 mmplayer_t *player = (mmplayer_t *)(data);
3372 GstMessage *msg = NULL;
3375 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3377 player->pipeline->mainbin &&
3378 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3381 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3383 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3384 while (!player->bus_msg_thread_exit) {
3385 g_mutex_lock(&player->bus_msg_q_lock);
3386 msg = g_queue_pop_head(player->bus_msg_q);
3387 g_mutex_unlock(&player->bus_msg_q_lock);
3389 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3392 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3393 /* handle the gst msg */
3394 __mmplayer_gst_bus_msg_callback(msg, player);
3395 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3396 gst_message_unref(msg);
3399 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3406 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3408 gint64 dur_nsec = 0;
3409 gint64 pos_nsec = 0;
3412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3414 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3415 return MM_ERROR_NONE;
3417 /* NOTE : duration cannot be zero except live streaming.
3418 * Since some element could have some timing problem with querying duration, try again.
3420 if (player->duration == 0) {
3421 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3422 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3423 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3424 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3425 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3426 player->pending_seek.is_pending = true;
3427 player->pending_seek.pos = position;
3428 player->seek_state = MMPLAYER_SEEK_NONE;
3429 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3430 return MM_ERROR_PLAYER_NO_OP;
3432 player->seek_state = MMPLAYER_SEEK_NONE;
3433 return MM_ERROR_PLAYER_SEEK;
3436 player->duration = dur_nsec;
3439 if (player->duration > 0 && player->duration < position) {
3440 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3441 return MM_ERROR_INVALID_ARGUMENT;
3444 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3445 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3446 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3447 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3448 player->seek_state = MMPLAYER_SEEK_NONE;
3449 return MM_ERROR_PLAYER_NO_OP;
3454 return MM_ERROR_NONE;
3458 __mmplayer_gst_check_seekable(mmplayer_t *player)
3460 GstQuery *query = NULL;
3461 gboolean seekable = FALSE;
3463 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3467 query = gst_query_new_seeking(GST_FORMAT_TIME);
3468 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3469 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3470 gst_query_unref(query);
3473 LOGW("non-seekable content");
3474 player->seek_state = MMPLAYER_SEEK_NONE;
3478 LOGW("failed to get seeking query");
3479 gst_query_unref(query); /* keep seeking operation */
3486 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3488 GstState element_state = GST_STATE_VOID_PENDING;
3489 GstState element_pending_state = GST_STATE_VOID_PENDING;
3490 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3495 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3497 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3500 ret = gst_element_set_state(element, state);
3501 if (ret == GST_STATE_CHANGE_FAILURE) {
3502 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3504 /* dump state of all element */
3505 _mmplayer_dump_pipeline_state(player);
3507 return MM_ERROR_PLAYER_INTERNAL;
3510 /* return here so state transition to be done in async mode */
3512 LOGD("async state transition. not waiting for state complete.");
3513 return MM_ERROR_NONE;
3516 /* wait for state transition */
3517 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3518 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3519 LOGE("failed to change [%s] element state to [%s] within %d sec",
3520 GST_ELEMENT_NAME(element),
3521 gst_element_state_get_name(state), timeout);
3523 LOGE(" [%s] state : %s pending : %s",
3524 GST_ELEMENT_NAME(element),
3525 gst_element_state_get_name(element_state),
3526 gst_element_state_get_name(element_pending_state));
3528 /* dump state of all element */
3529 _mmplayer_dump_pipeline_state(player);
3531 return MM_ERROR_PLAYER_INTERNAL;
3534 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3538 return MM_ERROR_NONE;
3542 _mmplayer_gst_start(mmplayer_t *player)
3544 int ret = MM_ERROR_NONE;
3545 gboolean async = FALSE;
3549 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3551 /* NOTE : if SetPosition was called before Start. do it now
3552 * streaming doesn't support it. so it should be always sync
3553 * !!create one more api to check if there is pending seek rather than checking variables
3555 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3556 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3557 ret = _mmplayer_gst_pause(player, FALSE);
3558 if (ret != MM_ERROR_NONE) {
3559 LOGE("failed to set state to PAUSED for pending seek");
3563 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3564 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3565 LOGW("failed to seek pending position. starting from the begin of content");
3568 LOGD("current state before doing transition");
3569 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3570 MMPLAYER_PRINT_STATE(player);
3572 /* set pipeline state to PLAYING */
3573 ret = _mmplayer_gst_set_state(player,
3574 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3575 if (ret != MM_ERROR_NONE) {
3576 LOGE("failed to set state to PLAYING");
3580 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3582 /* generating debug info before returning error */
3583 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3591 _mmplayer_gst_stop(mmplayer_t *player)
3593 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3594 MMHandleType attrs = 0;
3595 gboolean rewind = FALSE;
3597 int ret = MM_ERROR_NONE;
3601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3602 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3604 LOGD("current state before doing transition");
3605 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3606 MMPLAYER_PRINT_STATE(player);
3608 attrs = MMPLAYER_GET_ATTRS(player);
3610 LOGE("cannot get content attribute");
3611 return MM_ERROR_PLAYER_INTERNAL;
3614 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3615 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3617 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3618 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3621 if (player->es_player_push_mode)
3622 /* disable the async state transition because there could be no data in the pipeline */
3623 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3626 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3628 if (player->es_player_push_mode) {
3629 /* enable the async state transition as default operation */
3630 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3633 /* return if set_state has failed */
3634 if (ret != MM_ERROR_NONE) {
3635 LOGE("failed to set state.");
3641 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3642 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3643 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3644 LOGW("failed to rewind");
3645 ret = MM_ERROR_PLAYER_SEEK;
3650 player->sent_bos = FALSE;
3652 if (player->es_player_push_mode) //for cloudgame
3655 /* wait for seek to complete */
3656 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3657 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3658 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3660 LOGE("fail to stop player.");
3661 ret = MM_ERROR_PLAYER_INTERNAL;
3662 _mmplayer_dump_pipeline_state(player);
3665 /* generate dot file if enabled */
3666 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3674 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3676 int ret = MM_ERROR_NONE;
3680 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3681 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3683 LOGD("current state before doing transition");
3684 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3685 MMPLAYER_PRINT_STATE(player);
3687 /* set pipeline status to PAUSED */
3688 ret = _mmplayer_gst_set_state(player,
3689 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3694 if (ret != MM_ERROR_NONE) {
3695 GstMessage *msg = NULL;
3696 GTimer *timer = NULL;
3697 gdouble MAX_TIMEOUT_SEC = 3;
3699 LOGE("failed to set state to PAUSED");
3701 if (!player->bus_watcher) {
3702 LOGE("there is no bus msg thread. pipeline is shutting down.");
3706 if (player->msg_posted) {
3707 LOGE("error msg is already posted.");
3711 timer = g_timer_new();
3712 g_timer_start(timer);
3714 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3717 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3719 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3720 GError *error = NULL;
3722 /* parse error code */
3723 gst_message_parse_error(msg, &error, NULL);
3725 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3726 /* Note : the streaming error from the streaming source is handled
3727 * using __mmplayer_handle_streaming_error.
3729 __mmplayer_handle_streaming_error(player, msg, error);
3732 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3734 if (error->domain == GST_STREAM_ERROR)
3735 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3736 else if (error->domain == GST_RESOURCE_ERROR)
3737 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3738 else if (error->domain == GST_LIBRARY_ERROR)
3739 ret = __mmplayer_gst_handle_library_error(player, error->code);
3740 else if (error->domain == GST_CORE_ERROR)
3741 ret = __mmplayer_gst_handle_core_error(player, error->code);
3743 g_error_free(error);
3745 player->msg_posted = TRUE;
3747 gst_message_unref(msg);
3749 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3751 gst_object_unref(bus);
3752 g_timer_stop(timer);
3753 g_timer_destroy(timer);
3758 if (MMPLAYER_USE_DECODEBIN(player)) {
3759 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3760 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3761 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3764 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3767 /* generate dot file before returning error */
3768 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3776 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3778 int ret = MM_ERROR_NONE;
3783 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3784 MM_ERROR_PLAYER_NOT_INITIALIZED);
3786 LOGD("current state before doing transition");
3787 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3788 MMPLAYER_PRINT_STATE(player);
3791 LOGD("do async state transition to PLAYING");
3793 /* set pipeline state to PLAYING */
3794 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3796 ret = _mmplayer_gst_set_state(player,
3797 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3798 if (ret != MM_ERROR_NONE) {
3799 LOGE("failed to set state to PLAYING");
3804 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3807 /* generate dot file */
3808 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3815 /* sending event to one of sinkelements */
3817 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3819 GstEvent *event2 = NULL;
3820 GList *sinks = NULL;
3821 gboolean res = FALSE;
3824 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3825 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3827 /* While adding subtitles in live feeds seek is getting called.
3828 Adding defensive check in framework layer.*/
3829 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3830 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3831 LOGE("Should not send seek event during live playback");
3836 if (player->play_subtitle)
3837 event2 = gst_event_copy((const GstEvent *)event);
3839 sinks = player->sink_elements;
3841 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3843 if (GST_IS_ELEMENT(sink)) {
3844 /* keep ref to the event */
3845 gst_event_ref(event);
3847 if ((res = gst_element_send_event(sink, event))) {
3848 LOGD("sending event[%s] to sink element [%s] success!",
3849 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3851 /* rtsp case, async_done is not called after seek during pause state */
3852 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3853 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3854 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3855 LOGD("RTSP seek completed, after pause state..");
3856 player->seek_state = MMPLAYER_SEEK_NONE;
3857 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3863 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3864 sinks = g_list_next(sinks);
3871 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3872 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3875 sinks = g_list_next(sinks);
3878 /* Note : Textbin is not linked to the video or audio bin.
3879 * It needs to send the event to the text sink separately.
3881 if (player->play_subtitle && player->pipeline) {
3882 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3884 if (GST_IS_ELEMENT(text_sink)) {
3885 /* keep ref to the event */
3886 gst_event_ref(event2);
3888 if ((res = gst_element_send_event(text_sink, event2)))
3889 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3890 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3892 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3893 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3895 gst_event_unref(event2);
3899 gst_event_unref(event);
3907 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3908 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3909 gint64 cur, GstSeekType stop_type, gint64 stop)
3911 GstEvent *event = NULL;
3912 gboolean result = FALSE;
3916 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3918 if (player->pipeline && player->pipeline->textbin)
3919 __mmplayer_drop_subtitle(player, FALSE);
3921 event = gst_event_new_seek(rate, format, flags, cur_type,
3922 cur, stop_type, stop);
3924 result = _mmplayer_gst_send_event_to_sink(player, event);
3932 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3934 int ret = MM_ERROR_NONE;
3935 gint64 pos_nsec = 0;
3936 gboolean accurate = FALSE;
3937 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3940 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3941 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3943 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3944 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3947 ret = __mmplayer_gst_check_position(player, position);
3948 if (ret != MM_ERROR_NONE) {
3949 LOGW("result of check position info 0x%X", ret);
3950 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3953 if (!__mmplayer_gst_check_seekable(player))
3954 return MM_ERROR_PLAYER_NO_OP;
3956 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3957 position, player->playback_rate, player->duration);
3959 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3960 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3961 This causes problem is position calculation during normal pause resume scenarios also.
3962 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3963 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3964 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3965 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3966 LOGW("getting current position failed in seek");
3968 player->last_position = pos_nsec;
3969 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3972 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3973 LOGD("not completed seek");
3974 return MM_ERROR_PLAYER_DOING_SEEK;
3977 if (!internal_called)
3978 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3980 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3981 that's why set position through property. */
3982 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3983 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3984 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3985 (!player->videodec_linked) && (!player->audiodec_linked)) {
3987 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3988 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3990 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3991 player->seek_state = MMPLAYER_SEEK_NONE;
3992 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3994 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3996 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3998 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4000 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4001 GST_FORMAT_TIME, seek_flags,
4002 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4003 LOGE("failed to set position");
4008 /* NOTE : store last seeking point to overcome some bad operation
4009 * (returning zero when getting current position) of some elements
4011 player->last_position = position;
4013 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4014 if (player->playback_rate > 1.0)
4015 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4017 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4018 LOGD("buffering should be reset after seeking");
4019 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4020 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4024 return MM_ERROR_NONE;
4027 player->pending_seek.is_pending = true;
4028 player->pending_seek.pos = position;
4030 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4031 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4032 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4033 player->pending_seek.pos);
4035 return MM_ERROR_NONE;
4038 player->seek_state = MMPLAYER_SEEK_NONE;
4039 return MM_ERROR_PLAYER_SEEK;
4043 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4045 #define TRICKPLAY_OFFSET GST_MSECOND
4047 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4048 gint64 pos_nsec = 0;
4049 gboolean ret = TRUE;
4051 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4052 MM_ERROR_PLAYER_NOT_INITIALIZED);
4054 current_state = MMPLAYER_CURRENT_STATE(player);
4056 /* NOTE : query position except paused state to overcome some bad operation
4057 * please refer to below comments in details
4059 if (current_state != MM_PLAYER_STATE_PAUSED)
4060 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4062 /* NOTE : get last point to overcome some bad operation of some elements
4063 *(returning zero when getting current position in paused state
4064 * and when failed to get position during seeking
4066 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4067 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4069 if (player->playback_rate < 0.0)
4070 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4072 pos_nsec = player->last_position;
4075 pos_nsec = player->last_position;
4077 player->last_position = pos_nsec;
4079 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4082 if (player->duration > 0 && pos_nsec > player->duration)
4083 pos_nsec = player->duration;
4085 player->last_position = pos_nsec;
4088 *position = pos_nsec;
4090 return MM_ERROR_NONE;
4094 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4096 #define STREAMING_IS_FINISHED 0
4097 #define BUFFERING_MAX_PER 100
4098 #define DEFAULT_PER_VALUE -1
4099 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4101 mmplayer_gst_element_t *mainbin = NULL;
4102 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4103 gint64 buffered_total = 0;
4104 gint64 position = 0;
4105 gint buffered_sec = -1;
4106 GstBufferingMode mode = GST_BUFFERING_STREAM;
4107 gint64 content_size_time = player->duration;
4108 guint64 content_size_bytes = player->http_content_size;
4110 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4112 player->pipeline->mainbin,
4113 MM_ERROR_PLAYER_NOT_INITIALIZED);
4115 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4120 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4121 /* and rtsp is not ready yet. */
4122 LOGW("it's only used for http streaming case");
4123 return MM_ERROR_PLAYER_NO_OP;
4126 if (content_size_time <= 0 || content_size_bytes <= 0) {
4127 LOGW("there is no content size");
4128 return MM_ERROR_NONE;
4131 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4132 LOGW("fail to get current position");
4133 return MM_ERROR_NONE;
4136 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4137 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4139 mainbin = player->pipeline->mainbin;
4140 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4142 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4143 GstQuery *query = NULL;
4144 gint byte_in_rate = 0, byte_out_rate = 0;
4145 gint64 estimated_total = 0;
4147 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4148 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4149 LOGW("fail to get buffering query from queue2");
4151 gst_query_unref(query);
4152 return MM_ERROR_NONE;
4155 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4156 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4158 if (mode == GST_BUFFERING_STREAM) {
4159 /* using only queue in case of push mode(ts / mp3) */
4160 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4161 GST_FORMAT_BYTES, &buffered_total)) {
4162 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4163 end_per = 100 * buffered_total / content_size_bytes;
4166 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4168 guint num_of_ranges = 0;
4169 gint64 start_byte = 0, stop_byte = 0;
4171 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4172 if (estimated_total != STREAMING_IS_FINISHED) {
4173 /* buffered size info from queue2 */
4174 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4175 for (idx = 0; idx < num_of_ranges; idx++) {
4176 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4177 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4179 buffered_total += (stop_byte - start_byte);
4182 end_per = BUFFERING_MAX_PER;
4185 gst_query_unref(query);
4188 if (end_per == DEFAULT_PER_VALUE) {
4189 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4191 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4193 /* buffered size info from multiqueue */
4194 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4195 guint curr_size_bytes = 0;
4196 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4197 "curr-size-bytes", &curr_size_bytes, NULL);
4198 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4199 buffered_total += (gint64)curr_size_bytes;
4202 if (avg_byterate > 0)
4203 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4204 else if (player->total_maximum_bitrate > 0)
4205 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4206 else if (player->total_bitrate > 0)
4207 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4209 if (buffered_sec >= 0)
4210 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4214 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4215 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4217 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4218 buffered_total, buffered_sec, *start_pos, *end_pos);
4220 return MM_ERROR_NONE;
4224 _mmplayer_gst_create_source(mmplayer_t *player)
4226 GstElement *element = NULL;
4229 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4230 player->pipeline->mainbin, NULL);
4232 /* setup source for gapless play */
4233 switch (player->profile.uri_type) {
4235 case MM_PLAYER_URI_TYPE_FILE:
4236 element = __mmplayer_gst_make_file_src(player);
4238 case MM_PLAYER_URI_TYPE_URL_HTTP:
4239 element = __mmplayer_gst_make_http_src(player);
4242 LOGE("not support uri type %d", player->profile.uri_type);
4247 LOGE("failed to create source element");
4256 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4259 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4260 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4262 SECURE_LOGD("uri : %s", player->profile.uri);
4264 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4266 if ((player->v_stream_caps) &&
4267 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4268 return MM_ERROR_PLAYER_INTERNAL;
4270 if ((player->a_stream_caps) &&
4271 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4272 return MM_ERROR_PLAYER_INTERNAL;
4274 if ((player->s_stream_caps) &&
4275 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4276 return MM_ERROR_PLAYER_INTERNAL;
4279 return MM_ERROR_NONE;
4283 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4285 mmplayer_gst_element_t *mainbin = NULL;
4286 GstElement *autoplug_elem = NULL;
4289 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4290 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4292 mainbin = player->pipeline->mainbin;
4294 LOGD("uri type %d", player->profile.uri_type);
4296 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4297 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4298 return MM_ERROR_PLAYER_INTERNAL;
4301 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4302 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4305 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4306 if (!autoplug_elem) {
4307 LOGE("failed to create uridecodebin3 element");
4311 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4312 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4313 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4315 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4316 LOGE("failed to add uridecodebin to pipeline");
4320 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4321 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4322 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4324 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4325 LOGE("failed to create fakesink");
4328 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4330 /* take ownership of fakesink. we are reusing it */
4331 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4333 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4334 LOGE("failed to add fakesink to bin");
4335 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4340 return MM_ERROR_NONE;
4344 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4345 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4347 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4348 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4350 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4351 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4353 return MM_ERROR_PLAYER_INTERNAL;
4357 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4359 mmplayer_gst_element_t *mainbin = NULL;
4360 GstElement *src_elem = NULL;
4361 GstElement *autoplug_elem = NULL;
4362 GList *element_bucket = NULL;
4363 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4366 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4367 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4369 LOGD("uri type %d", player->profile.uri_type);
4371 /* create source element */
4372 switch (player->profile.uri_type) {
4373 case MM_PLAYER_URI_TYPE_URL_RTSP:
4374 src_elem = __mmplayer_gst_make_rtsp_src(player);
4376 case MM_PLAYER_URI_TYPE_URL_HTTP:
4377 src_elem = __mmplayer_gst_make_http_src(player);
4379 case MM_PLAYER_URI_TYPE_FILE:
4380 src_elem = __mmplayer_gst_make_file_src(player);
4382 case MM_PLAYER_URI_TYPE_SS:
4384 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4385 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4387 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4391 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4392 LOGD("get timeout from ini");
4393 http_timeout = player->ini.http_timeout;
4396 /* setting property to streaming source */
4397 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4400 case MM_PLAYER_URI_TYPE_MEM:
4402 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4404 src_elem = gst_element_factory_make("appsrc", "mem-source");
4406 LOGE("failed to create appsrc element");
4410 g_object_set(src_elem, "stream-type", stream_type,
4411 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4413 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4414 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4415 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4416 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4420 LOGE("not support uri type");
4425 LOGE("failed to create source element");
4426 return MM_ERROR_PLAYER_INTERNAL;
4429 mainbin = player->pipeline->mainbin;
4431 /* take source element */
4432 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4434 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4435 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4436 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4438 /* create next element for auto-plugging */
4439 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4440 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4441 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4442 if (!autoplug_elem) {
4443 LOGE("failed to create typefind element");
4447 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4448 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4449 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4450 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4451 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4452 if (!autoplug_elem) {
4453 LOGE("failed to create decodebin");
4457 /* default size of mq in decodebin is 2M
4458 * but it can cause blocking issue during seeking depends on content. */
4459 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4462 if (autoplug_elem) {
4463 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4464 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4465 mainbin[autoplug_elem_id].gst = autoplug_elem;
4467 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4470 /* add elements to pipeline */
4471 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4472 LOGE("failed to add elements to pipeline");
4476 /* linking elements in the bucket by added order. */
4477 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4478 LOGE("failed to link some elements");
4482 /* FIXME: need to check whether this is required or not. */
4483 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4484 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4485 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4486 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4487 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4489 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4490 LOGE("failed to create fakesink");
4493 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4495 /* take ownership of fakesink. we are reusing it */
4496 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4498 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4499 LOGE("failed to add fakesink to bin");
4500 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4505 g_list_free(element_bucket);
4508 return MM_ERROR_NONE;
4511 g_list_free(element_bucket);
4513 if (mainbin[MMPLAYER_M_SRC].gst)
4514 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4516 if (mainbin[autoplug_elem_id].gst)
4517 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4519 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4520 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4522 mainbin[MMPLAYER_M_SRC].gst = NULL;
4523 mainbin[autoplug_elem_id].gst = NULL;
4524 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4526 return MM_ERROR_PLAYER_INTERNAL;
4530 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4533 mmplayer_gst_element_t *mainbin = NULL;
4536 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4537 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4539 mainbin = player->pipeline->mainbin;
4541 /* connect bus callback */
4542 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4544 LOGE("cannot get bus from pipeline");
4545 return MM_ERROR_PLAYER_INTERNAL;
4548 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4549 (GstBusFunc)__mmplayer_gst_msg_push, player,
4550 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4551 if (player->bus_watcher == 0) {
4552 LOGE("failed to add bus watch");
4553 return MM_ERROR_PLAYER_INTERNAL;
4556 g_mutex_init(&player->bus_watcher_mutex);
4557 g_cond_init(&player->bus_watcher_cond);
4559 player->context.thread_default = g_main_context_get_thread_default();
4560 if (player->context.thread_default == NULL) {
4561 player->context.thread_default = g_main_context_default();
4562 LOGD("thread-default context is the global default context");
4564 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4566 /* set sync handler to get tag synchronously */
4567 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4568 gst_object_unref(GST_OBJECT(bus));
4570 /* create gst bus_msb_cb thread */
4571 g_mutex_init(&player->bus_msg_thread_mutex);
4572 g_cond_init(&player->bus_msg_thread_cond);
4573 player->bus_msg_thread_exit = FALSE;
4574 player->bus_msg_thread =
4575 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4576 if (!player->bus_msg_thread) {
4577 LOGE("failed to create gst BUS msg thread");
4578 g_mutex_clear(&player->bus_msg_thread_mutex);
4579 g_cond_clear(&player->bus_msg_thread_cond);
4580 return MM_ERROR_PLAYER_INTERNAL;
4584 return MM_ERROR_NONE;
4588 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4590 int ret = MM_ERROR_NONE;
4591 mmplayer_gst_element_t *mainbin = NULL;
4592 MMMessageParamType msg_param = {0,};
4593 GstElement *element = NULL;
4594 MMHandleType attrs = 0;
4596 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4600 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4601 LOGE("player is not initialized");
4605 mainbin = player->pipeline->mainbin;
4606 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4608 attrs = MMPLAYER_GET_ATTRS(player);
4610 LOGE("fail to get attributes");
4614 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4616 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4617 LOGE("failed to parse profile");
4618 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4622 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4623 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4624 LOGE("dash or hls is not supportable");
4625 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4629 if (!MMPLAYER_USE_DECODEBIN(player)) {
4630 ret = _mmplayer_gst_build_pipeline_with_src(player);
4631 if (ret != MM_ERROR_NONE)
4634 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4635 LOGE("Failed to change state of uridecodebin3 element");
4641 element = _mmplayer_gst_create_source(player);
4643 LOGE("no source element was created");
4647 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4648 LOGE("failed to add source element to pipeline");
4649 gst_object_unref(GST_OBJECT(element));
4654 /* take source element */
4655 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4656 mainbin[MMPLAYER_M_SRC].gst = element;
4660 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4661 if (player->streamer == NULL) {
4662 player->streamer = _mm_player_streaming_create();
4663 _mm_player_streaming_initialize(player->streamer, TRUE);
4666 elem_idx = MMPLAYER_M_TYPEFIND;
4667 element = gst_element_factory_make("typefind", "typefinder");
4668 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4669 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4671 elem_idx = MMPLAYER_M_AUTOPLUG;
4672 element = _mmplayer_gst_make_decodebin(player);
4675 /* check autoplug element is OK */
4677 LOGE("can not create element(%d)", elem_idx);
4681 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4682 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4683 gst_object_unref(GST_OBJECT(element));
4688 mainbin[elem_idx].id = elem_idx;
4689 mainbin[elem_idx].gst = element;
4691 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4692 LOGE("Failed to link src - autoplug(or typefind)");
4696 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4697 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4698 LOGE("Failed to change state of src element");
4702 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4703 LOGE("Failed to change state of decodebin");
4708 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4709 LOGE("Failed to change state of src element");
4714 player->gapless.stream_changed = TRUE;
4715 player->gapless.running = TRUE;
4721 _mmplayer_set_reconfigure_state(player, FALSE);
4722 if (!player->msg_posted) {
4723 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4724 player->msg_posted = TRUE;