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);
875 /* if retval is FALSE, it will be dropped for performance. */
877 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
879 gboolean retval = FALSE;
881 if (!(player->pipeline && player->pipeline->mainbin)) {
882 LOGE("player pipeline handle is null");
886 switch (GST_MESSAGE_TYPE(message)) {
887 case GST_MESSAGE_TAG:
888 case GST_MESSAGE_EOS:
889 case GST_MESSAGE_ERROR:
890 case GST_MESSAGE_WARNING:
891 case GST_MESSAGE_CLOCK_LOST:
892 case GST_MESSAGE_NEW_CLOCK:
893 case GST_MESSAGE_ELEMENT:
894 case GST_MESSAGE_DURATION_CHANGED:
895 case GST_MESSAGE_ASYNC_START:
896 case GST_MESSAGE_STREAM_COLLECTION:
899 case GST_MESSAGE_ASYNC_DONE:
900 case GST_MESSAGE_STATE_CHANGED:
901 /* we only handle messages from pipeline */
902 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
907 case GST_MESSAGE_BUFFERING:
909 gint buffer_percent = 0;
912 gst_message_parse_buffering(message, &buffer_percent);
913 if (buffer_percent != MAX_BUFFER_PERCENT) {
914 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
918 if (!MMPLAYER_CMD_TRYLOCK(player)) {
919 LOGW("can't get cmd lock, send msg to bus");
923 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
924 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
925 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
928 MMPLAYER_CMD_UNLOCK(player);
932 case GST_MESSAGE_STREAMS_SELECTED:
934 if (MMPLAYER_USE_DECODEBIN(player))
935 break; /* drop msg */
936 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
937 LOGD("pipeline is still under construction for adaptive streaming");
942 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
943 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
944 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
946 gint64 dur_bytes = 0L;
948 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
949 LOGE("fail to get duration.");
951 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
952 * use file information was already set on Q2 when it was created. */
953 _mm_player_streaming_set_queue2(player->streamer,
954 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
955 TRUE, /* use_buffering */
956 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
957 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
960 LOGD("GST_MESSAGE_STREAMS_SELECTED");
961 player->no_more_pad = TRUE;
962 _mmplayer_set_reconfigure_state(player, FALSE);
963 _mmplayer_pipeline_complete(NULL, player);
976 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
978 guint64 data_size = 0;
981 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
983 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
985 if (MMPLAYER_IS_HTTP_STREAMING(player))
986 data_size = player->http_content_size;
988 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
989 if (!player->streamer->is_adaptive_streaming) {
990 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
994 /* adaptivedemux2 is used for buffering in uridecodebin3 */
995 if (!player->streamer->buffering_req.is_pre_buffering) {
996 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
997 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
998 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1004 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1006 int ret = MM_ERROR_NONE;
1007 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1008 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1009 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1010 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1012 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1013 LOGW("do nothing for buffering msg");
1014 ret = MM_ERROR_PLAYER_INVALID_STATE;
1018 prev_state = MMPLAYER_PREV_STATE(player);
1019 current_state = MMPLAYER_CURRENT_STATE(player);
1020 target_state = MMPLAYER_TARGET_STATE(player);
1021 pending_state = MMPLAYER_PENDING_STATE(player);
1023 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1024 MMPLAYER_STATE_GET_NAME(prev_state),
1025 MMPLAYER_STATE_GET_NAME(current_state),
1026 MMPLAYER_STATE_GET_NAME(pending_state),
1027 MMPLAYER_STATE_GET_NAME(target_state),
1028 player->streamer->buffering_state);
1030 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1031 /* NOTE : if buffering has done, player has to go to target state. */
1032 switch (target_state) {
1033 case MM_PLAYER_STATE_PAUSED:
1035 switch (pending_state) {
1036 case MM_PLAYER_STATE_PLAYING:
1037 _mmplayer_gst_pause(player, TRUE);
1040 case MM_PLAYER_STATE_PAUSED:
1041 LOGD("player is already going to paused state, there is nothing to do.");
1044 case MM_PLAYER_STATE_NONE:
1045 case MM_PLAYER_STATE_NULL:
1046 case MM_PLAYER_STATE_READY:
1048 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1054 case MM_PLAYER_STATE_PLAYING:
1056 switch (pending_state) {
1057 case MM_PLAYER_STATE_NONE:
1059 if (current_state != MM_PLAYER_STATE_PLAYING)
1060 _mmplayer_gst_resume(player, TRUE);
1064 case MM_PLAYER_STATE_PAUSED:
1065 /* NOTE: It should be worked as asynchronously.
1066 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1068 if (current_state == MM_PLAYER_STATE_PLAYING) {
1069 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1070 * The current state should be changed to paused purposely to prevent state conflict.
1072 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1074 _mmplayer_gst_resume(player, TRUE);
1077 case MM_PLAYER_STATE_PLAYING:
1078 LOGD("player is already going to playing state, there is nothing to do.");
1081 case MM_PLAYER_STATE_NULL:
1082 case MM_PLAYER_STATE_READY:
1084 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1090 case MM_PLAYER_STATE_NULL:
1091 case MM_PLAYER_STATE_READY:
1092 case MM_PLAYER_STATE_NONE:
1094 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1098 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1099 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1101 switch (pending_state) {
1102 case MM_PLAYER_STATE_NONE:
1104 if (current_state != MM_PLAYER_STATE_PAUSED) {
1105 /* rtsp streaming pause makes rtsp server stop sending data. */
1106 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1107 LOGD("set pause state during buffering");
1108 _mmplayer_gst_pause(player, TRUE);
1114 case MM_PLAYER_STATE_PLAYING:
1115 /* rtsp streaming pause makes rtsp server stop sending data. */
1116 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1117 _mmplayer_gst_pause(player, TRUE);
1120 case MM_PLAYER_STATE_PAUSED:
1123 case MM_PLAYER_STATE_NULL:
1124 case MM_PLAYER_STATE_READY:
1126 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1135 static stream_variant_t *
1136 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1138 stream_variant_t *var_info = NULL;
1139 g_return_val_if_fail(self != NULL, NULL);
1141 var_info = g_new0(stream_variant_t, 1);
1142 if (!var_info) return NULL;
1143 var_info->bandwidth = self->bandwidth;
1144 var_info->width = self->width;
1145 var_info->height = self->height;
1150 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1156 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1157 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1159 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1160 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1161 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1163 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1164 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1165 player->http_content_size = (bytes > 0) ? bytes : 0;
1168 /* handling audio clip which has vbr. means duration is keep changing */
1169 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1178 __mmplayer_eos_timer_cb(gpointer u_data)
1180 mmplayer_t *player = NULL;
1181 MMHandleType attrs = 0;
1184 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1186 player = (mmplayer_t *)u_data;
1187 attrs = MMPLAYER_GET_ATTRS(player);
1189 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1193 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1194 if (ret_value != MM_ERROR_NONE)
1195 LOGE("seeking to 0 failed in repeat play");
1198 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1201 /* we are returning FALSE as we need only one posting */
1206 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1208 MMPLAYER_RETURN_IF_FAIL(player);
1210 /* post now if delay is zero */
1211 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1212 LOGD("eos delay is zero. posting EOS now");
1213 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1215 if (player->audio_decoded_cb)
1216 _mmplayer_cancel_eos_timer(player);
1221 /* cancel if existing */
1222 _mmplayer_cancel_eos_timer(player);
1224 /* init new timeout */
1225 /* NOTE : consider give high priority to this timer */
1226 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1228 player->eos_timer = g_timeout_add(delay_in_ms,
1229 __mmplayer_eos_timer_cb, player);
1231 player->context.global_default = g_main_context_default();
1232 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1234 /* check timer is valid. if not, send EOS now */
1235 if (player->eos_timer == 0) {
1236 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1237 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1242 __mmplayer_gst_pending_seek(mmplayer_t *player)
1244 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1245 int ret = MM_ERROR_NONE;
1249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1251 if (!player->pending_seek.is_pending) {
1252 LOGD("pending seek is not reserved. nothing to do.");
1256 /* check player state if player could pending seek or not. */
1257 current_state = MMPLAYER_CURRENT_STATE(player);
1259 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1260 LOGW("try to pending seek in %s state, try next time. ",
1261 MMPLAYER_STATE_GET_NAME(current_state));
1265 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1267 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1268 if (ret != MM_ERROR_NONE)
1269 LOGE("failed to seek pending position. just keep staying current position.");
1271 player->pending_seek.is_pending = false;
1279 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1281 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1283 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1285 audiobin = player->pipeline->audiobin; /* can be null */
1286 videobin = player->pipeline->videobin; /* can be null */
1287 textbin = player->pipeline->textbin; /* can be null */
1289 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1291 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1292 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1294 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1295 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1297 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1298 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1304 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1306 mmplayer_gst_element_t *textbin;
1309 MMPLAYER_RETURN_IF_FAIL(player &&
1311 player->pipeline->textbin);
1313 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1315 textbin = player->pipeline->textbin;
1318 LOGD("Drop subtitle text after getting EOS");
1320 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1321 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1323 player->is_subtitle_force_drop = TRUE;
1325 if (player->is_subtitle_force_drop == TRUE) {
1326 LOGD("Enable subtitle data path without drop");
1328 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1329 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1331 LOGD("non-connected with external display");
1333 player->is_subtitle_force_drop = FALSE;
1339 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1341 MMHandleType attrs = 0;
1346 /* NOTE : EOS event is coming multiple time. watch out it */
1347 /* check state. we only process EOS when pipeline state goes to PLAYING */
1348 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1349 LOGD("EOS received on non-playing state. ignoring it");
1353 if (player->pipeline && player->pipeline->textbin)
1354 __mmplayer_drop_subtitle(player, TRUE);
1356 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1357 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1359 /* rewind if repeat count is greater then zero */
1360 /* get play count */
1361 attrs = MMPLAYER_GET_ATTRS(player);
1363 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1365 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1367 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1368 if (player->playback_rate < 0.0) {
1369 player->resumed_by_rewind = TRUE;
1370 _mmplayer_set_mute((MMHandleType)player, false);
1371 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1374 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1377 player->sent_bos = FALSE;
1379 LOGD("do not post eos msg for repeating");
1384 if (player->pipeline)
1385 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1387 /* post eos message to application */
1388 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1390 /* reset last position */
1391 player->last_position = 0;
1398 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1400 GError *error = NULL;
1401 gchar *debug = NULL;
1405 /* generating debug info before returning error */
1406 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1408 /* get error code */
1409 gst_message_parse_error(msg, &error, &debug);
1411 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1412 /* Note : the streaming error from the streaming source is handled
1413 * using __mmplayer_handle_streaming_error.
1415 __mmplayer_handle_streaming_error(player, msg, error);
1417 /* dump state of all element */
1418 _mmplayer_dump_pipeline_state(player);
1420 /* translate gst error code to msl error code. then post it
1421 * to application if needed
1423 __mmplayer_handle_gst_error(player, msg, error);
1426 LOGE("error debug : %s", debug);
1429 MMPLAYER_FREEIF(debug);
1430 g_error_free(error);
1437 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1439 MMMessageParamType msg_param = {0, };
1440 int bRet = MM_ERROR_NONE;
1443 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1445 if (!MMPLAYER_IS_STREAMING(player)) {
1446 LOGW("this is not streaming playback.");
1450 MMPLAYER_CMD_LOCK(player);
1452 if (!player->streamer) {
1453 LOGW("Pipeline is shutting down");
1454 MMPLAYER_CMD_UNLOCK(player);
1458 /* ignore the remained buffering message till getting 100% msg */
1459 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1460 gint buffer_percent = 0;
1462 gst_message_parse_buffering(msg, &buffer_percent);
1464 if (buffer_percent == MAX_BUFFER_PERCENT) {
1465 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1466 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1467 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1469 MMPLAYER_CMD_UNLOCK(player);
1473 /* ignore the remained buffering message */
1474 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1475 gint buffer_percent = 0;
1477 gst_message_parse_buffering(msg, &buffer_percent);
1479 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1480 player->streamer->buffering_percent, buffer_percent);
1482 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1483 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1484 player->streamer->buffering_req.is_pre_buffering = FALSE;
1486 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1488 LOGD("interrupted buffering - ignored the remained buffering msg!");
1489 MMPLAYER_CMD_UNLOCK(player);
1494 __mmplayer_update_buffer_setting(player, msg);
1496 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1498 if (bRet == MM_ERROR_NONE) {
1499 msg_param.connection.buffering = player->streamer->buffering_percent;
1500 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1502 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1503 player->pending_resume &&
1504 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1506 player->is_external_subtitle_added_now = FALSE;
1507 player->pending_resume = FALSE;
1508 _mmplayer_resume((MMHandleType)player);
1511 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1512 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1514 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1515 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1516 player->seek_state = MMPLAYER_SEEK_NONE;
1517 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1518 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1519 /* Considering the async state transition in case of RTSP.
1520 After getting state change gst msg, seek completed msg will be posted. */
1521 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1525 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1526 if (!player->streamer) {
1527 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1528 MMPLAYER_CMD_UNLOCK(player);
1532 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1534 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1535 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1537 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1538 msg_param.connection.buffering = player->streamer->buffering_percent;
1539 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1541 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1544 msg_param.connection.buffering = player->streamer->buffering_percent;
1545 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1548 MMPLAYER_CMD_UNLOCK(player);
1556 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1558 mmplayer_gst_element_t *mainbin;
1559 const GValue *voldstate, *vnewstate, *vpending;
1560 GstState oldstate = GST_STATE_NULL;
1561 GstState newstate = GST_STATE_NULL;
1562 GstState pending = GST_STATE_NULL;
1565 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1567 mainbin = player->pipeline->mainbin;
1569 /* we only handle messages from pipeline */
1570 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1573 /* get state info from msg */
1574 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1575 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1576 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1578 if (!voldstate || !vnewstate) {
1579 LOGE("received msg has wrong format.");
1583 oldstate = (GstState)voldstate->data[0].v_int;
1584 newstate = (GstState)vnewstate->data[0].v_int;
1586 pending = (GstState)vpending->data[0].v_int;
1588 LOGD("state changed [%s] : %s ---> %s final : %s",
1589 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1590 gst_element_state_get_name((GstState)oldstate),
1591 gst_element_state_get_name((GstState)newstate),
1592 gst_element_state_get_name((GstState)pending));
1594 if (newstate == GST_STATE_PLAYING) {
1595 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1597 int retVal = MM_ERROR_NONE;
1598 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1600 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1602 if (MM_ERROR_NONE != retVal)
1603 LOGE("failed to seek pending position. just keep staying current position.");
1605 player->pending_seek.is_pending = false;
1609 if (oldstate == newstate) {
1610 LOGD("pipeline reports state transition to old state");
1615 case GST_STATE_PAUSED:
1617 gboolean prepare_async = FALSE;
1619 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1620 // managed prepare async case
1621 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1622 LOGD("checking prepare mode for async transition - %d", prepare_async);
1625 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1626 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1628 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1629 _mm_player_streaming_set_content_bitrate(player->streamer,
1630 player->total_maximum_bitrate, player->total_bitrate);
1632 if (player->pending_seek.is_pending) {
1633 LOGW("trying to do pending seek");
1634 MMPLAYER_CMD_LOCK(player);
1635 __mmplayer_gst_pending_seek(player);
1636 MMPLAYER_CMD_UNLOCK(player);
1642 case GST_STATE_PLAYING:
1644 if (MMPLAYER_IS_STREAMING(player)) {
1645 // managed prepare async case when buffering is completed
1646 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1647 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1648 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1649 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1651 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1653 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1654 if (player->streamer->buffering_percent < 100) {
1656 MMMessageParamType msg_param = {0, };
1657 LOGW("Posting Buffering Completed Message to Application !!!");
1659 msg_param.connection.buffering = 100;
1660 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1665 if (player->gapless.stream_changed) {
1666 _mmplayer_update_content_attrs(player, ATTR_ALL);
1667 player->gapless.stream_changed = FALSE;
1670 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1671 player->seek_state = MMPLAYER_SEEK_NONE;
1672 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1676 case GST_STATE_VOID_PENDING:
1677 case GST_STATE_NULL:
1678 case GST_STATE_READY:
1688 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1690 const gchar *structure_name;
1691 gint count = 0, idx = 0;
1694 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1696 if (gst_message_get_structure(msg) == NULL)
1699 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1700 if (!structure_name)
1703 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1705 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1706 const GValue *var_info = NULL;
1708 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1709 if (var_info != NULL) {
1710 if (player->adaptive_info.var_list)
1711 g_list_free_full(player->adaptive_info.var_list, g_free);
1713 /* share addr or copy the list */
1714 player->adaptive_info.var_list =
1715 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1717 count = g_list_length(player->adaptive_info.var_list);
1719 stream_variant_t *temp = NULL;
1721 /* print out for debug */
1722 LOGD("num of variant_info %d", count);
1723 for (idx = 0; idx < count; idx++) {
1724 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1726 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1732 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1733 gint num_buffers = 0;
1734 gint extra_num_buffers = 0;
1736 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1737 LOGD("video_num_buffers : %d", num_buffers);
1738 mm_player_set_attribute((MMHandleType)player, NULL,
1739 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1742 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1743 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1744 mm_player_set_attribute((MMHandleType)player, NULL,
1745 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1750 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1751 _mmplayer_track_update_text_attr_info(player, msg);
1753 /* custom message */
1754 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1755 MMMessageParamType msg_param = {0,};
1756 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1757 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1760 /* custom message for RTSP attribute :
1761 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1762 sdp which has contents info is received when rtsp connection is opened.
1763 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1764 if (!strcmp(structure_name, "rtspsrc_properties")) {
1765 g_autofree gchar *audio_codec = NULL;
1766 g_autofree gchar *video_codec = NULL;
1767 g_autofree gchar *video_frame_size = NULL;
1769 gst_structure_get(gst_message_get_structure(msg),
1770 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1771 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1772 player->streaming_type = _mmplayer_get_stream_service_type(player);
1774 gst_structure_get(gst_message_get_structure(msg),
1775 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1776 LOGD("rtsp_audio_codec : %s", audio_codec);
1778 mm_player_set_attribute((MMHandleType)player, NULL,
1779 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1781 gst_structure_get(gst_message_get_structure(msg),
1782 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1783 LOGD("rtsp_video_codec : %s", video_codec);
1785 mm_player_set_attribute((MMHandleType)player, NULL,
1786 "content_video_codec", video_codec, strlen(video_codec), NULL);
1788 gst_structure_get(gst_message_get_structure(msg),
1789 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1790 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1791 if (video_frame_size) {
1792 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1793 mm_player_set_attribute((MMHandleType)player, NULL,
1794 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1795 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1797 g_strfreev(res_str);
1806 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1808 mmplayer_gst_element_t *mainbin;
1811 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1813 mainbin = player->pipeline->mainbin;
1815 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1817 /* we only handle messages from pipeline */
1818 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1821 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1822 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1823 player->seek_state = MMPLAYER_SEEK_NONE;
1824 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1825 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1826 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1827 LOGD("sync %s state(%s) with parent state(%s)",
1828 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1829 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1830 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1832 /* In case of streaming, pause is required before finishing seeking by buffering.
1833 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1834 Because the buffering state is controlled according to the state transition for force resume,
1835 the decodebin state should be paused as player state. */
1836 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1839 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1840 (player->streamer) &&
1841 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1842 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1843 GstQuery *query = NULL;
1844 gboolean busy = FALSE;
1847 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1848 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1849 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1850 gst_query_parse_buffering_percent(query, &busy, &percent);
1851 gst_query_unref(query);
1853 LOGD("buffered percent(%s): %d",
1854 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1858 __mmplayer_handle_buffering_playback(player);
1861 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1871 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1873 GValue val = { 0, };
1875 guint indent = GPOINTER_TO_UINT(user_data);
1877 if (!gst_tag_list_copy_value(&val, tags, tag))
1880 if (G_VALUE_HOLDS_STRING(&val))
1881 str = g_value_dup_string(&val);
1883 str = gst_value_serialize(&val);
1885 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1887 g_value_unset(&val);
1892 __mmplayer_dump_collection(GstStreamCollection * collection)
1896 GstTagList *tags = NULL;
1898 GstCaps *caps = NULL;
1900 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1901 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1902 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1903 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1904 gst_stream_get_stream_flags(stream));
1905 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1907 caps = gst_stream_get_caps(stream);
1909 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1910 gst_caps_unref(caps);
1914 tags = gst_stream_get_tags(stream);
1917 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1918 gst_tag_list_unref(tags);
1925 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1926 GstStream *stream, GParamSpec *pspec, gpointer data)
1928 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1929 gst_stream_get_stream_id(stream), pspec->name, collection);
1930 if (g_str_equal(pspec->name, "caps")) {
1931 GstCaps *caps = gst_stream_get_caps(stream);
1932 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1933 gst_caps_unref(caps);
1937 if (g_str_equal (pspec->name, "tags")) {
1938 GstTagList *tags = gst_stream_get_tags(stream);
1941 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1942 gst_tag_list_unref(tags);
1949 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1951 mmplayer_t *player = (mmplayer_t *)(data);
1953 MMPLAYER_RETURN_IF_FAIL(player);
1954 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1956 switch (GST_MESSAGE_TYPE(msg)) {
1957 case GST_MESSAGE_UNKNOWN:
1958 LOGD("unknown message received");
1961 case GST_MESSAGE_EOS:
1962 LOGD("GST_MESSAGE_EOS received");
1963 __mmplayer_gst_handle_eos_message(player, msg);
1966 case GST_MESSAGE_ERROR:
1967 _mmplayer_set_reconfigure_state(player, FALSE);
1968 __mmplayer_gst_handle_error_message(player, msg);
1971 case GST_MESSAGE_WARNING:
1974 GError *error = NULL;
1976 gst_message_parse_warning(msg, &error, &debug);
1978 LOGD("warning : %s", error->message);
1979 LOGD("debug : %s", debug);
1981 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1983 MMPLAYER_FREEIF(debug);
1984 g_error_free(error);
1988 case GST_MESSAGE_TAG:
1990 LOGD("GST_MESSAGE_TAG");
1991 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1992 LOGW("failed to extract tags from gstmessage");
1996 case GST_MESSAGE_BUFFERING:
1997 __mmplayer_gst_handle_buffering_message(player, msg);
2000 case GST_MESSAGE_STATE_CHANGED:
2001 __mmplayer_gst_handle_state_message(player, msg);
2004 case GST_MESSAGE_CLOCK_LOST:
2006 GstClock *clock = NULL;
2007 gboolean need_new_clock = FALSE;
2009 gst_message_parse_clock_lost(msg, &clock);
2010 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2012 if (!player->videodec_linked)
2013 need_new_clock = TRUE;
2014 else if (!player->ini.use_system_clock)
2015 need_new_clock = TRUE;
2017 if (need_new_clock) {
2018 LOGD("Provide clock is TRUE, do pause->resume");
2019 _mmplayer_gst_pause(player, FALSE);
2020 _mmplayer_gst_resume(player, FALSE);
2025 case GST_MESSAGE_NEW_CLOCK:
2027 GstClock *clock = NULL;
2028 gst_message_parse_new_clock(msg, &clock);
2029 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2033 case GST_MESSAGE_ELEMENT:
2034 __mmplayer_gst_handle_element_message(player, msg);
2037 case GST_MESSAGE_DURATION_CHANGED:
2039 LOGD("GST_MESSAGE_DURATION_CHANGED");
2040 if (!__mmplayer_gst_handle_duration(player, msg))
2041 LOGW("failed to update duration");
2045 case GST_MESSAGE_ASYNC_START:
2046 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2049 case GST_MESSAGE_ASYNC_DONE:
2050 __mmplayer_gst_handle_async_done_message(player, msg);
2052 case GST_MESSAGE_STREAM_COLLECTION:
2054 GstStreamCollection *collection = NULL;
2055 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2057 gst_message_parse_stream_collection(msg, &collection);
2059 __mmplayer_dump_collection(collection);
2060 if (player->collection && player->stream_notify_id) {
2061 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2062 player->stream_notify_id = 0;
2064 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2065 if (player->collection) {
2066 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2067 (GCallback)__mmplayer_stream_notify_cb, player);
2069 gst_object_unref(collection);
2072 case GST_MESSAGE_STREAMS_SELECTED:
2074 GstStreamCollection *collection = NULL;
2075 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2077 gst_message_parse_streams_selected(msg, &collection);
2079 guint i = 0, len = 0;
2080 len = gst_message_streams_selected_get_size(msg);
2081 for (i = 0; i < len; i++) {
2082 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2083 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2084 gst_object_unref(stream);
2086 gst_object_unref (collection);
2091 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2092 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2093 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2094 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2095 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2096 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2097 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2098 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2099 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2100 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2101 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2102 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2103 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2104 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2105 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2112 /* should not call 'gst_message_unref(msg)' */
2116 static GstBusSyncReply
2117 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2119 mmplayer_t *player = (mmplayer_t *)data;
2120 GstBusSyncReply reply = GST_BUS_DROP;
2122 if (!(player->pipeline && player->pipeline->mainbin)) {
2123 LOGE("player pipeline handle is null");
2124 return GST_BUS_PASS;
2127 if (!__mmplayer_gst_check_useful_message(player, message)) {
2128 gst_message_unref(message);
2129 return GST_BUS_DROP;
2132 switch (GST_MESSAGE_TYPE(message)) {
2133 case GST_MESSAGE_TAG:
2134 __mmplayer_gst_extract_tag_from_msg(player, message);
2138 GstTagList *tags = NULL;
2140 gst_message_parse_tag(message, &tags);
2142 LOGE("TAGS received from element \"%s\".",
2143 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2145 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2146 gst_tag_list_unref(tags);
2154 case GST_MESSAGE_DURATION_CHANGED:
2155 __mmplayer_gst_handle_duration(player, message);
2157 case GST_MESSAGE_ELEMENT:
2159 const gchar *klass = NULL;
2160 klass = gst_element_factory_get_metadata
2161 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2162 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2163 reply = GST_BUS_PASS;
2166 __mmplayer_gst_handle_element_message(player, message);
2169 case GST_MESSAGE_ASYNC_DONE:
2170 /* NOTE:Don't call gst_callback directly
2171 * because previous frame can be showed even though this message is received for seek.
2174 reply = GST_BUS_PASS;
2178 if (reply == GST_BUS_DROP)
2179 gst_message_unref(message);
2185 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2187 GstElement *appsrc = element;
2188 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2189 GstBuffer *buffer = NULL;
2190 GstFlowReturn ret = GST_FLOW_OK;
2193 MMPLAYER_RETURN_IF_FAIL(element);
2194 MMPLAYER_RETURN_IF_FAIL(buf);
2196 buffer = gst_buffer_new();
2198 if (buf->offset < 0 || buf->len < 0) {
2199 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2203 if (buf->offset >= buf->len) {
2204 LOGD("call eos appsrc");
2205 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2209 if (buf->len - buf->offset < size)
2210 len = buf->len - buf->offset;
2212 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2213 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2214 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2217 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2219 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2225 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2227 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2229 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2231 buf->offset = (int)size;
2237 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2239 mmplayer_t *player = (mmplayer_t *)user_data;
2240 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2241 MMMessageParamType msg_param = {0,};
2242 guint64 current_level_bytes = 0;
2244 MMPLAYER_RETURN_IF_FAIL(player);
2246 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2247 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2248 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2249 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2251 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2255 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2257 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2259 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2260 msg_param.buffer_status.stream_type = stream_type;
2261 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2262 msg_param.buffer_status.bytes = current_level_bytes;
2264 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2268 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2270 mmplayer_t *player = (mmplayer_t *)user_data;
2271 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2272 MMMessageParamType msg_param = {0,};
2273 guint64 current_level_bytes = 0;
2275 MMPLAYER_RETURN_IF_FAIL(player);
2277 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2278 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2279 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2280 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2282 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2286 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2288 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2290 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2291 msg_param.buffer_status.stream_type = stream_type;
2292 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2293 msg_param.buffer_status.bytes = current_level_bytes;
2295 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2299 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2301 mmplayer_t *player = (mmplayer_t *)user_data;
2302 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2303 MMMessageParamType msg_param = {0,};
2305 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2307 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2308 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2309 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2310 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2312 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2316 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2318 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2319 msg_param.seek_data.stream_type = stream_type;
2320 msg_param.seek_data.offset = position;
2322 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2328 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2330 #define MAX_LEN_NAME 20
2332 gboolean ret = FALSE;
2333 GstPad *sinkpad = NULL;
2334 gchar *prefix = NULL;
2335 gchar dec_name[MAX_LEN_NAME] = {0, };
2336 main_element_id_e elem_id = MMPLAYER_M_NUM;
2338 mmplayer_gst_element_t *mainbin = NULL;
2339 GstElement *decodebin = NULL;
2340 GstCaps *dec_caps = NULL;
2344 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2346 player->pipeline->mainbin, FALSE);
2347 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2349 mainbin = player->pipeline->mainbin;
2351 case MM_PLAYER_STREAM_TYPE_AUDIO:
2353 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2355 case MM_PLAYER_STREAM_TYPE_VIDEO:
2357 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2360 LOGE("invalid type %d", type);
2364 if (mainbin[elem_id].gst) {
2365 LOGE("elem(%d) is already created", elem_id);
2369 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2371 /* create decodebin */
2372 decodebin = gst_element_factory_make("decodebin", dec_name);
2374 LOGE("failed to create %s", dec_name);
2378 /* raw pad handling signal */
2379 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2380 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2382 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2383 before looking for any elements that can handle that stream.*/
2384 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2385 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2387 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2388 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2389 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2391 /* This signal is emitted when a element is added to the bin.*/
2392 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2393 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2395 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2396 LOGE("failed to add new decodebin");
2400 dec_caps = gst_pad_query_caps(srcpad, NULL);
2403 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2405 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2406 gst_caps_unref(dec_caps);
2409 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2411 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2412 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2415 gst_object_unref(GST_OBJECT(sinkpad));
2417 gst_element_sync_state_with_parent(decodebin);
2419 mainbin[elem_id].id = elem_id;
2420 mainbin[elem_id].gst = decodebin;
2427 gst_object_unref(GST_OBJECT(sinkpad));
2430 gst_element_set_state(decodebin, GST_STATE_NULL);
2431 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2432 gst_object_unref(decodebin);
2440 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2442 #define MAX_LEN_NAME 20
2443 mmplayer_gst_element_t *mainbin = NULL;
2444 gchar *prefix = NULL;
2445 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2447 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2448 GstElement *src = NULL, *queue = NULL;
2449 GstPad *srcpad = NULL;
2452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2453 player->pipeline->mainbin, FALSE);
2455 mainbin = player->pipeline->mainbin;
2457 LOGD("type(%d) path is creating", type);
2459 case MM_PLAYER_STREAM_TYPE_AUDIO:
2461 if (mainbin[MMPLAYER_M_SRC].gst)
2462 src_id = MMPLAYER_M_2ND_SRC;
2464 src_id = MMPLAYER_M_SRC;
2465 queue_id = MMPLAYER_M_A_BUFFER;
2467 case MM_PLAYER_STREAM_TYPE_VIDEO:
2469 src_id = MMPLAYER_M_SRC;
2470 queue_id = MMPLAYER_M_V_BUFFER;
2472 case MM_PLAYER_STREAM_TYPE_TEXT:
2473 prefix = "subtitle";
2474 src_id = MMPLAYER_M_SUBSRC;
2475 queue_id = MMPLAYER_M_S_BUFFER;
2478 LOGE("invalid type %d", type);
2482 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2483 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2486 src = gst_element_factory_make("appsrc", src_name);
2488 LOGF("failed to create %s", src_name);
2492 mainbin[src_id].id = src_id;
2493 mainbin[src_id].gst = src;
2495 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2496 "caps", caps, NULL);
2498 /* size of many video frames are larger than default blocksize as 4096 */
2499 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2500 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2502 if (player->media_stream_buffer_max_size[type] > 0)
2503 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2505 if (player->media_stream_buffer_min_percent[type] > 0)
2506 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2508 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2509 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2511 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2512 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2513 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2514 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2515 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2516 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2519 queue = gst_element_factory_make("queue2", queue_name);
2521 LOGE("failed to create %s", queue_name);
2524 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2526 mainbin[queue_id].id = queue_id;
2527 mainbin[queue_id].gst = queue;
2529 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2530 LOGE("failed to add src");
2534 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2535 LOGE("failed to add queue");
2539 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2540 LOGE("failed to link src and queue");
2544 /* create decoder */
2545 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2547 LOGE("failed to get srcpad of queue");
2551 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2552 _mmplayer_gst_create_decoder(player, srcpad, caps);
2554 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2555 LOGE("failed to create decoder");
2556 gst_object_unref(GST_OBJECT(srcpad));
2560 gst_object_unref(GST_OBJECT(srcpad));
2564 if (mainbin[src_id].gst) {
2565 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2566 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2567 gst_object_unref(mainbin[src_id].gst);
2568 mainbin[src_id].gst = NULL;
2571 if (mainbin[queue_id].gst) {
2572 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2573 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2574 gst_object_unref(mainbin[queue_id].gst);
2575 mainbin[queue_id].gst = NULL;
2582 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2584 GstPad *sinkpad = NULL;
2585 GstCaps *caps = NULL;
2586 GstElement *new_element = NULL;
2587 GstStructure *str = NULL;
2588 const gchar *name = NULL;
2590 mmplayer_t *player = (mmplayer_t *)data;
2594 MMPLAYER_RETURN_IF_FAIL(element && pad);
2595 MMPLAYER_RETURN_IF_FAIL(player &&
2597 player->pipeline->mainbin);
2599 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2600 * num_dynamic_pad will decreased after creating a sinkbin.
2602 player->num_dynamic_pad++;
2603 LOGD("stream count inc : %d", player->num_dynamic_pad);
2605 caps = gst_pad_query_caps(pad, NULL);
2606 MMPLAYER_CHECK_NULL(caps);
2608 str = gst_caps_get_structure(caps, 0);
2609 name = gst_structure_get_string(str, "media");
2611 LOGE("cannot get mimetype from structure.");
2615 if (strstr(name, "video")) {
2617 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2619 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2620 if (player->v_stream_caps) {
2621 gst_caps_unref(player->v_stream_caps);
2622 player->v_stream_caps = NULL;
2625 new_element = gst_element_factory_make("fakesink", NULL);
2626 player->num_dynamic_pad--;
2631 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2632 LOGE("failed to autoplug for caps");
2636 gst_caps_unref(caps);
2641 /* execute new_element if created*/
2643 LOGD("adding new element to pipeline");
2645 /* set state to READY before add to bin */
2646 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2648 /* add new element to the pipeline */
2649 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2650 LOGE("failed to add autoplug element to bin");
2654 /* get pad from element */
2655 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2657 LOGE("failed to get sinkpad from autoplug element");
2662 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2663 LOGE("failed to link autoplug element");
2667 gst_object_unref(sinkpad);
2670 /* run. setting PLAYING here since streaming source is live source */
2671 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2675 gst_caps_unref(caps);
2681 STATE_CHANGE_FAILED:
2683 /* FIXIT : take care if new_element has already added to pipeline */
2685 gst_object_unref(GST_OBJECT(new_element));
2688 gst_object_unref(GST_OBJECT(sinkpad));
2691 gst_caps_unref(caps);
2693 /* FIXIT : how to inform this error to MSL ????? */
2694 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2695 * then post an error to application
2700 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2702 mmplayer_t *player = (mmplayer_t *)data;
2706 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2707 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2708 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2709 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2711 * [1] audio and video will be dumped with filesink.
2712 * [2] autoplugging is done by just using pad caps.
2713 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2714 * and the video will be dumped via filesink.
2716 if (player->num_dynamic_pad == 0) {
2717 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2719 if (!_mmplayer_gst_remove_fakesink(player,
2720 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2721 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2722 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2723 * source element are not same. To overcome this situation, this function will called
2724 * several places and several times. Therefore, this is not an error case.
2729 /* create dot before error-return. for debugging */
2730 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2732 player->no_more_pad = TRUE;
2738 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2740 GstElement *element = NULL;
2741 gchar *user_agent = NULL;
2742 MMHandleType attrs = 0;
2745 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2747 /* get profile attribute */
2748 attrs = MMPLAYER_GET_ATTRS(player);
2750 LOGE("failed to get content attribute");
2754 element = gst_element_factory_make("rtspsrc", "rtsp source");
2756 LOGE("failed to create rtspsrc element");
2761 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2763 SECURE_LOGD("user_agent : %s", user_agent);
2765 /* setting property to streaming source */
2766 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2768 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2770 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2771 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2772 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2773 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2779 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2781 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2783 mmplayer_t *player = (mmplayer_t *)data;
2784 MMHandleType attrs = 0;
2785 gchar *user_agent, *cookies, **cookie_list;
2786 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2787 user_agent = cookies = NULL;
2791 MMPLAYER_RETURN_IF_FAIL(player);
2793 LOGD("source element %s", GST_ELEMENT_NAME(source));
2795 attrs = MMPLAYER_GET_ATTRS(player);
2797 LOGE("failed to get content attribute");
2801 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2802 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2804 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2805 http_timeout = player->ini.http_timeout;
2807 SECURE_LOGD("cookies : %s", cookies);
2808 SECURE_LOGD("user_agent : %s", user_agent);
2809 LOGD("timeout : %d", http_timeout);
2811 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2813 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2814 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2815 g_strfreev(cookie_list);
2819 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2825 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2827 mmplayer_t *player = (mmplayer_t *)data;
2828 gchar *user_agent = NULL;
2829 MMHandleType attrs = 0;
2832 MMPLAYER_RETURN_IF_FAIL(player);
2834 attrs = MMPLAYER_GET_ATTRS(player);
2836 LOGE("failed to get content attribute");
2840 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2842 SECURE_LOGD("user_agent : %s", user_agent);
2845 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2851 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2853 mmplayer_t *player = (mmplayer_t *)data;
2854 GstElement *source = NULL;
2857 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2859 g_object_get(orig, pspec->name, &source, NULL);
2861 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2862 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2864 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2865 __mmplayer_http_src_setup(source, data);
2866 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2867 __mmplayer_rtsp_src_setup(source, data);
2868 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2869 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2870 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2871 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2872 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2874 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2875 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2876 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2877 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2879 gst_object_unref (source);
2885 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
2887 const gchar *stream1_id = gst_stream_get_stream_id((GstStream *)stream1);
2888 const gchar *stream2_id = gst_stream_get_stream_id((GstStream *)stream2);
2890 return (g_strcmp0(stream1_id, stream2_id) == 0);
2894 __mmplayer_has_duplicated_stream(mmplayer_t *player, GstStreamType stype, GstStream *stream)
2896 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2898 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2901 case GST_STREAM_TYPE_AUDIO:
2902 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2904 case GST_STREAM_TYPE_VIDEO:
2905 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2907 case GST_STREAM_TYPE_TEXT:
2908 type = MM_PLAYER_TRACK_TYPE_TEXT;
2911 LOGD("Skip not supported stream stype");
2915 return g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL);
2919 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2920 GstStream * stream, gpointer data)
2922 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2923 GstStreamType stype = gst_stream_get_stream_type(stream);
2924 mmplayer_t *player = (mmplayer_t *)data;
2925 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2926 GstCaps *caps = gst_stream_get_caps(stream);
2927 GstStructure *caps_structure = NULL;
2928 gchar *caps_str = NULL;
2930 LOGD("Stream type %s flags 0x%x",
2931 gst_stream_type_get_name(stype),
2932 gst_stream_get_stream_flags(stream));
2933 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2935 if (__mmplayer_has_duplicated_stream(player, stype, stream)) {
2936 LOGD("Already added stream, skip it");
2942 caps_str = gst_caps_to_string(caps);
2943 caps_structure = gst_caps_get_structure(caps, 0);
2944 const gchar *mime = gst_structure_get_name(caps_structure);
2946 LOGD(" caps: %s", caps_str);
2948 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2949 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2950 LOGW("skip [%s] by unsupported codec keyword [%s]",
2951 mime, player->ini.unsupported_codec_keyword[idx]);
2953 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2961 case GST_STREAM_TYPE_AUDIO:
2963 gint samplerate = 0;
2966 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2968 if (caps_structure) {
2969 gst_structure_get_int(caps_structure, "rate", &samplerate);
2970 gst_structure_get_int(caps_structure, "channels", &channels);
2972 if (channels > 0 && samplerate == 0) {
2973 LOGW("Skip corrupted audio stream");
2977 if (g_strrstr(caps_str, "mobile-xmf"))
2978 mm_player_set_attribute((MMHandleType)player, NULL,
2979 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2983 case GST_STREAM_TYPE_VIDEO:
2988 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2990 /* do not support multi track video */
2991 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2994 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2996 /* don't make video because of not required */
2997 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2998 (!player->set_mode.video_export)) {
2999 LOGD("no need video decoding, skip video stream");
3003 if (caps_structure) {
3004 gst_structure_get_int(caps_structure, "width", &width);
3007 if (player->v_stream_caps) {
3008 gst_caps_unref(player->v_stream_caps);
3009 player->v_stream_caps = NULL;
3012 player->v_stream_caps = gst_caps_copy(caps);
3013 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3018 case GST_STREAM_TYPE_TEXT:
3019 type = MM_PLAYER_TRACK_TYPE_TEXT;
3022 LOGW("Skip not supported stream type");
3026 _mmplayer_track_update_stream(player, type, stream);
3028 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3029 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3030 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3031 _mmplayer_set_audio_attrs(player, caps);
3038 gst_caps_unref(caps);
3040 LOGD("ret %d", ret);
3045 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3046 GstStream * stream, gpointer data)
3048 mmplayer_t *player = (mmplayer_t *)data;
3049 GstStreamType stype = gst_stream_get_stream_type(stream);
3052 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3054 LOGD("stream type %s", gst_stream_type_get_name(stype));
3056 /* public does not support audio hw decoder at the moment */
3058 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3059 LOGW("video decoder resource is already acquired, skip it.");
3063 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3064 LOGE("failed to acquire video decoder resource");
3067 player->interrupted_by_resource = FALSE;
3073 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3075 GstIterator *iter = NULL;
3076 GValue item = {0, };
3077 GstElement *ch_element = NULL;
3078 GstElementFactory *ch_factory = NULL;
3081 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3083 iter = gst_bin_iterate_recurse(bin);
3084 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3086 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3087 ch_element = g_value_get_object(&item);
3088 ch_factory = gst_element_get_factory(ch_element);
3089 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3090 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3091 LOGD("Find %s element", element_name);
3095 g_value_reset(&item);
3097 gst_iterator_free(iter);
3103 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3105 mmplayer_t *player = (mmplayer_t *)data;
3107 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3109 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3110 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3111 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3113 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3114 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3115 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3118 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3120 mmplayer_t *player = (mmplayer_t *)data;
3121 int video_codec_type = 0;
3122 int audio_codec_type = 0;
3124 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3126 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3127 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3129 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3131 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3132 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3133 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3134 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3136 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3137 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3141 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3143 gchar *factory_name = NULL;
3144 mmplayer_t *player = (mmplayer_t *)data;
3147 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3149 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3151 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3153 if (g_strrstr(factory_name, "urisourcebin")) {
3154 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3156 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3158 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3160 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3162 LOGW("failed to find decodebin3");
3164 } else if (g_strrstr(factory_name, "parsebin")) {
3165 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3166 __mmplayer_parsebin_setup(GST_BIN(element), data);
3168 _mmplayer_gst_element_added(child, element, data);
3173 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3177 MMPLAYER_RETURN_IF_FAIL(player);
3178 MMPLAYER_RETURN_IF_FAIL(removed_element);
3180 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3182 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3183 GList *node = player->signals[type];
3185 GList *next_node = node->next;
3186 mmplayer_signal_item_t *item = node->data;
3187 if (item && item->obj == G_OBJECT(removed_element)) {
3188 player->signals[type] = g_list_delete_link(player->signals[type], node);
3189 MMPLAYER_FREEIF(item);
3199 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3201 mmplayer_t *player = (mmplayer_t *)data;
3205 MMPLAYER_RETURN_IF_FAIL(player);
3207 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3209 __mmplayer_delete_signal_connection(player, element);
3215 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3217 GstElement *uridecodebin3 = NULL;
3220 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3222 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3223 if (!uridecodebin3) {
3224 LOGE("failed to create uridecodebin3");
3229 SECURE_LOGD("uri : %s", player->profile.uri);
3231 /* setting property to streaming source */
3232 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3233 "message-forward", TRUE,
3234 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3235 "use-buffering", TRUE, NULL);
3237 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3238 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3240 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3241 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3243 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3244 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3246 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3247 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3249 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3250 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3252 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3253 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3255 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3256 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3258 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3259 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3261 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3262 LOGW("[DASH] this is still experimental feature");
3265 return uridecodebin3;
3269 __mmplayer_gst_make_http_src(mmplayer_t *player)
3271 #define MAX_RETRY_COUNT 10
3272 GstElement *element = NULL;
3273 MMHandleType attrs = 0;
3274 gchar *user_agent, *cookies, **cookie_list;
3275 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3277 user_agent = cookies = NULL;
3281 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3283 /* get profile attribute */
3284 attrs = MMPLAYER_GET_ATTRS(player);
3286 LOGE("failed to get content attribute");
3290 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3292 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3294 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3299 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3300 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3302 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3303 http_timeout = player->ini.http_timeout;
3306 SECURE_LOGD("location : %s", player->profile.uri);
3307 SECURE_LOGD("cookies : %s", cookies);
3308 SECURE_LOGD("user_agent : %s", user_agent);
3309 LOGD("timeout : %d", http_timeout);
3311 /* setting property to streaming source */
3312 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3313 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3314 "retries", MAX_RETRY_COUNT, NULL);
3316 /* parsing cookies */
3317 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3318 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3319 g_strfreev(cookie_list);
3323 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3325 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3326 LOGW("[DASH] this is still experimental feature");
3333 __mmplayer_gst_make_file_src(mmplayer_t *player)
3335 GstElement *element = NULL;
3338 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3340 LOGD("using filesrc for 'file://' handler");
3341 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3342 LOGE("failed to get storage info");
3346 element = gst_element_factory_make("filesrc", "source");
3348 LOGE("failed to create filesrc");
3352 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3359 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3361 mmplayer_t *player = (mmplayer_t *)data;
3363 g_return_val_if_fail(player, FALSE);
3364 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3365 gst_message_ref(msg);
3367 g_mutex_lock(&player->bus_msg_q_lock);
3368 g_queue_push_tail(player->bus_msg_q, msg);
3369 g_mutex_unlock(&player->bus_msg_q_lock);
3371 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3372 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3373 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3377 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3379 mmplayer_t *player = (mmplayer_t *)(data);
3380 GstMessage *msg = NULL;
3383 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3385 player->pipeline->mainbin &&
3386 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3389 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3391 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3392 while (!player->bus_msg_thread_exit) {
3393 g_mutex_lock(&player->bus_msg_q_lock);
3394 msg = g_queue_pop_head(player->bus_msg_q);
3395 g_mutex_unlock(&player->bus_msg_q_lock);
3397 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3400 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3401 /* handle the gst msg */
3402 __mmplayer_gst_bus_msg_callback(msg, player);
3403 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3404 gst_message_unref(msg);
3407 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3414 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3416 gint64 dur_nsec = 0;
3417 gint64 pos_nsec = 0;
3420 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3422 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3423 return MM_ERROR_NONE;
3425 /* NOTE : duration cannot be zero except live streaming.
3426 * Since some element could have some timing problem with querying duration, try again.
3428 if (player->duration == 0) {
3429 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3430 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3431 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3432 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3433 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3434 player->pending_seek.is_pending = true;
3435 player->pending_seek.pos = position;
3436 player->seek_state = MMPLAYER_SEEK_NONE;
3437 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3438 return MM_ERROR_PLAYER_NO_OP;
3440 player->seek_state = MMPLAYER_SEEK_NONE;
3441 return MM_ERROR_PLAYER_SEEK;
3444 player->duration = dur_nsec;
3447 if (player->duration > 0 && player->duration < position) {
3448 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3449 return MM_ERROR_INVALID_ARGUMENT;
3452 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3453 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3454 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3455 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3456 player->seek_state = MMPLAYER_SEEK_NONE;
3457 return MM_ERROR_PLAYER_NO_OP;
3462 return MM_ERROR_NONE;
3466 __mmplayer_gst_check_seekable(mmplayer_t *player)
3468 GstQuery *query = NULL;
3469 gboolean seekable = FALSE;
3471 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3475 query = gst_query_new_seeking(GST_FORMAT_TIME);
3476 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3477 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3478 gst_query_unref(query);
3481 LOGW("non-seekable content");
3482 player->seek_state = MMPLAYER_SEEK_NONE;
3486 LOGW("failed to get seeking query");
3487 gst_query_unref(query); /* keep seeking operation */
3494 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3496 GstState element_state = GST_STATE_VOID_PENDING;
3497 GstState element_pending_state = GST_STATE_VOID_PENDING;
3498 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3502 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3503 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3505 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3508 ret = gst_element_set_state(element, state);
3509 if (ret == GST_STATE_CHANGE_FAILURE) {
3510 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3512 /* dump state of all element */
3513 _mmplayer_dump_pipeline_state(player);
3515 return MM_ERROR_PLAYER_INTERNAL;
3518 /* return here so state transition to be done in async mode */
3520 LOGD("async state transition. not waiting for state complete.");
3521 return MM_ERROR_NONE;
3524 /* wait for state transition */
3525 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3526 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3527 LOGE("failed to change [%s] element state to [%s] within %d sec",
3528 GST_ELEMENT_NAME(element),
3529 gst_element_state_get_name(state), timeout);
3531 LOGE(" [%s] state : %s pending : %s",
3532 GST_ELEMENT_NAME(element),
3533 gst_element_state_get_name(element_state),
3534 gst_element_state_get_name(element_pending_state));
3536 /* dump state of all element */
3537 _mmplayer_dump_pipeline_state(player);
3539 return MM_ERROR_PLAYER_INTERNAL;
3542 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3546 return MM_ERROR_NONE;
3550 _mmplayer_gst_start(mmplayer_t *player)
3552 int ret = MM_ERROR_NONE;
3553 gboolean async = FALSE;
3557 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3559 /* NOTE : if SetPosition was called before Start. do it now
3560 * streaming doesn't support it. so it should be always sync
3561 * !!create one more api to check if there is pending seek rather than checking variables
3563 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3564 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3565 ret = _mmplayer_gst_pause(player, FALSE);
3566 if (ret != MM_ERROR_NONE) {
3567 LOGE("failed to set state to PAUSED for pending seek");
3571 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3572 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3573 LOGW("failed to seek pending position. starting from the begin of content");
3576 LOGD("current state before doing transition");
3577 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3578 MMPLAYER_PRINT_STATE(player);
3580 /* set pipeline state to PLAYING */
3581 ret = _mmplayer_gst_set_state(player,
3582 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3583 if (ret != MM_ERROR_NONE) {
3584 LOGE("failed to set state to PLAYING");
3588 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3590 /* generating debug info before returning error */
3591 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3599 _mmplayer_gst_stop(mmplayer_t *player)
3601 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3602 MMHandleType attrs = 0;
3603 gboolean rewind = FALSE;
3605 int ret = MM_ERROR_NONE;
3609 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3610 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3612 LOGD("current state before doing transition");
3613 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3614 MMPLAYER_PRINT_STATE(player);
3616 attrs = MMPLAYER_GET_ATTRS(player);
3618 LOGE("cannot get content attribute");
3619 return MM_ERROR_PLAYER_INTERNAL;
3622 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3623 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3625 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3626 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3629 if (player->es_player_push_mode)
3630 /* disable the async state transition because there could be no data in the pipeline */
3631 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3634 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3636 if (player->es_player_push_mode) {
3637 /* enable the async state transition as default operation */
3638 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3641 /* return if set_state has failed */
3642 if (ret != MM_ERROR_NONE) {
3643 LOGE("failed to set state.");
3649 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3650 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3651 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3652 LOGW("failed to rewind");
3653 ret = MM_ERROR_PLAYER_SEEK;
3658 player->sent_bos = FALSE;
3660 if (player->es_player_push_mode) //for cloudgame
3663 /* wait for seek to complete */
3664 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3665 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3666 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3668 LOGE("fail to stop player.");
3669 ret = MM_ERROR_PLAYER_INTERNAL;
3670 _mmplayer_dump_pipeline_state(player);
3673 /* generate dot file if enabled */
3674 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3682 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3684 int ret = MM_ERROR_NONE;
3688 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3689 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3691 LOGD("current state before doing transition");
3692 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3693 MMPLAYER_PRINT_STATE(player);
3695 /* set pipeline status to PAUSED */
3696 ret = _mmplayer_gst_set_state(player,
3697 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3702 if (ret != MM_ERROR_NONE) {
3703 GstMessage *msg = NULL;
3704 GTimer *timer = NULL;
3705 gdouble MAX_TIMEOUT_SEC = 3;
3707 LOGE("failed to set state to PAUSED");
3709 if (!player->bus_watcher) {
3710 LOGE("there is no bus msg thread. pipeline is shutting down.");
3714 if (player->msg_posted) {
3715 LOGE("error msg is already posted.");
3719 timer = g_timer_new();
3720 g_timer_start(timer);
3722 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3725 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3727 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3728 GError *error = NULL;
3730 /* parse error code */
3731 gst_message_parse_error(msg, &error, NULL);
3733 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3734 /* Note : the streaming error from the streaming source is handled
3735 * using __mmplayer_handle_streaming_error.
3737 __mmplayer_handle_streaming_error(player, msg, error);
3740 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3742 if (error->domain == GST_STREAM_ERROR)
3743 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3744 else if (error->domain == GST_RESOURCE_ERROR)
3745 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3746 else if (error->domain == GST_LIBRARY_ERROR)
3747 ret = __mmplayer_gst_handle_library_error(player, error->code);
3748 else if (error->domain == GST_CORE_ERROR)
3749 ret = __mmplayer_gst_handle_core_error(player, error->code);
3751 g_error_free(error);
3753 player->msg_posted = TRUE;
3755 gst_message_unref(msg);
3757 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3759 gst_object_unref(bus);
3760 g_timer_stop(timer);
3761 g_timer_destroy(timer);
3766 if (MMPLAYER_USE_DECODEBIN(player)) {
3767 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3768 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3769 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3772 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3775 /* generate dot file before returning error */
3776 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3784 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3786 int ret = MM_ERROR_NONE;
3791 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3792 MM_ERROR_PLAYER_NOT_INITIALIZED);
3794 LOGD("current state before doing transition");
3795 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3796 MMPLAYER_PRINT_STATE(player);
3799 LOGD("do async state transition to PLAYING");
3801 /* set pipeline state to PLAYING */
3802 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3804 ret = _mmplayer_gst_set_state(player,
3805 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3806 if (ret != MM_ERROR_NONE) {
3807 LOGE("failed to set state to PLAYING");
3812 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3815 /* generate dot file */
3816 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3823 /* sending event to one of sinkelements */
3825 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3827 GstEvent *event2 = NULL;
3828 GList *sinks = NULL;
3829 gboolean res = FALSE;
3832 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3833 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3835 /* While adding subtitles in live feeds seek is getting called.
3836 Adding defensive check in framework layer.*/
3837 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3838 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3839 LOGE("Should not send seek event during live playback");
3844 if (player->play_subtitle)
3845 event2 = gst_event_copy((const GstEvent *)event);
3847 sinks = player->sink_elements;
3849 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3851 if (GST_IS_ELEMENT(sink)) {
3852 /* keep ref to the event */
3853 gst_event_ref(event);
3855 if ((res = gst_element_send_event(sink, event))) {
3856 LOGD("sending event[%s] to sink element [%s] success!",
3857 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3859 /* rtsp case, async_done is not called after seek during pause state */
3860 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3861 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3862 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3863 LOGD("RTSP seek completed, after pause state..");
3864 player->seek_state = MMPLAYER_SEEK_NONE;
3865 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3871 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3872 sinks = g_list_next(sinks);
3879 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3880 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3883 sinks = g_list_next(sinks);
3886 /* Note : Textbin is not linked to the video or audio bin.
3887 * It needs to send the event to the text sink separately.
3889 if (player->play_subtitle && player->pipeline) {
3890 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3892 if (GST_IS_ELEMENT(text_sink)) {
3893 /* keep ref to the event */
3894 gst_event_ref(event2);
3896 if ((res = gst_element_send_event(text_sink, event2)))
3897 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3898 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3900 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3901 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3903 gst_event_unref(event2);
3907 gst_event_unref(event);
3915 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3916 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3917 gint64 cur, GstSeekType stop_type, gint64 stop)
3919 GstEvent *event = NULL;
3920 gboolean result = FALSE;
3924 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3926 if (player->pipeline && player->pipeline->textbin)
3927 __mmplayer_drop_subtitle(player, FALSE);
3929 event = gst_event_new_seek(rate, format, flags, cur_type,
3930 cur, stop_type, stop);
3932 result = _mmplayer_gst_send_event_to_sink(player, event);
3940 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3942 int ret = MM_ERROR_NONE;
3943 gint64 pos_nsec = 0;
3944 gboolean accurate = FALSE;
3945 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3948 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3949 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3951 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3952 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3955 ret = __mmplayer_gst_check_position(player, position);
3956 if (ret != MM_ERROR_NONE) {
3957 LOGW("result of check position info 0x%X", ret);
3958 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3961 if (!__mmplayer_gst_check_seekable(player))
3962 return MM_ERROR_PLAYER_NO_OP;
3964 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3965 position, player->playback_rate, player->duration);
3967 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3968 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3969 This causes problem is position calculation during normal pause resume scenarios also.
3970 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3971 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3972 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3973 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3974 LOGW("getting current position failed in seek");
3976 player->last_position = pos_nsec;
3977 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3980 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3981 LOGD("not completed seek");
3982 return MM_ERROR_PLAYER_DOING_SEEK;
3985 if (!internal_called)
3986 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3988 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3989 that's why set position through property. */
3990 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3991 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3992 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3993 (!player->videodec_linked) && (!player->audiodec_linked)) {
3995 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3996 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3998 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3999 player->seek_state = MMPLAYER_SEEK_NONE;
4000 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4002 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4004 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4006 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4008 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4009 GST_FORMAT_TIME, seek_flags,
4010 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4011 LOGE("failed to set position");
4016 /* NOTE : store last seeking point to overcome some bad operation
4017 * (returning zero when getting current position) of some elements
4019 player->last_position = position;
4021 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4022 if (player->playback_rate > 1.0)
4023 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4025 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4026 LOGD("buffering should be reset after seeking");
4027 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4028 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4032 return MM_ERROR_NONE;
4035 player->pending_seek.is_pending = true;
4036 player->pending_seek.pos = position;
4038 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4039 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4040 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4041 player->pending_seek.pos);
4043 return MM_ERROR_NONE;
4046 player->seek_state = MMPLAYER_SEEK_NONE;
4047 return MM_ERROR_PLAYER_SEEK;
4051 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4053 #define TRICKPLAY_OFFSET GST_MSECOND
4055 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4056 gint64 pos_nsec = 0;
4057 gboolean ret = TRUE;
4059 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4060 MM_ERROR_PLAYER_NOT_INITIALIZED);
4062 current_state = MMPLAYER_CURRENT_STATE(player);
4064 /* NOTE : query position except paused state to overcome some bad operation
4065 * please refer to below comments in details
4067 if (current_state != MM_PLAYER_STATE_PAUSED)
4068 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4070 /* NOTE : get last point to overcome some bad operation of some elements
4071 *(returning zero when getting current position in paused state
4072 * and when failed to get position during seeking
4074 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4075 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4077 if (player->playback_rate < 0.0)
4078 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4080 pos_nsec = player->last_position;
4083 pos_nsec = player->last_position;
4085 player->last_position = pos_nsec;
4087 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4090 if (player->duration > 0 && pos_nsec > player->duration)
4091 pos_nsec = player->duration;
4093 player->last_position = pos_nsec;
4096 *position = pos_nsec;
4098 return MM_ERROR_NONE;
4102 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4104 #define STREAMING_IS_FINISHED 0
4105 #define BUFFERING_MAX_PER 100
4106 #define DEFAULT_PER_VALUE -1
4107 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4109 mmplayer_gst_element_t *mainbin = NULL;
4110 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4111 gint64 buffered_total = 0;
4112 gint64 position = 0;
4113 gint buffered_sec = -1;
4114 GstBufferingMode mode = GST_BUFFERING_STREAM;
4115 gint64 content_size_time = player->duration;
4116 guint64 content_size_bytes = player->http_content_size;
4118 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4120 player->pipeline->mainbin,
4121 MM_ERROR_PLAYER_NOT_INITIALIZED);
4123 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4128 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4129 /* and rtsp is not ready yet. */
4130 LOGW("it's only used for http streaming case");
4131 return MM_ERROR_PLAYER_NO_OP;
4134 if (content_size_time <= 0 || content_size_bytes <= 0) {
4135 LOGW("there is no content size");
4136 return MM_ERROR_NONE;
4139 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4140 LOGW("fail to get current position");
4141 return MM_ERROR_NONE;
4144 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4145 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4147 mainbin = player->pipeline->mainbin;
4148 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4150 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4151 GstQuery *query = NULL;
4152 gint byte_in_rate = 0, byte_out_rate = 0;
4153 gint64 estimated_total = 0;
4155 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4156 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4157 LOGW("fail to get buffering query from queue2");
4159 gst_query_unref(query);
4160 return MM_ERROR_NONE;
4163 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4164 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4166 if (mode == GST_BUFFERING_STREAM) {
4167 /* using only queue in case of push mode(ts / mp3) */
4168 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4169 GST_FORMAT_BYTES, &buffered_total)) {
4170 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4171 end_per = 100 * buffered_total / content_size_bytes;
4174 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4176 guint num_of_ranges = 0;
4177 gint64 start_byte = 0, stop_byte = 0;
4179 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4180 if (estimated_total != STREAMING_IS_FINISHED) {
4181 /* buffered size info from queue2 */
4182 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4183 for (idx = 0; idx < num_of_ranges; idx++) {
4184 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4185 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4187 buffered_total += (stop_byte - start_byte);
4190 end_per = BUFFERING_MAX_PER;
4193 gst_query_unref(query);
4196 if (end_per == DEFAULT_PER_VALUE) {
4197 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4199 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4201 /* buffered size info from multiqueue */
4202 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4203 guint curr_size_bytes = 0;
4204 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4205 "curr-size-bytes", &curr_size_bytes, NULL);
4206 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4207 buffered_total += curr_size_bytes;
4210 if (avg_byterate > 0)
4211 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4212 else if (player->total_maximum_bitrate > 0)
4213 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4214 else if (player->total_bitrate > 0)
4215 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4217 if (buffered_sec >= 0)
4218 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4222 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4223 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4225 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4226 buffered_total, buffered_sec, *start_pos, *end_pos);
4228 return MM_ERROR_NONE;
4232 _mmplayer_gst_create_source(mmplayer_t *player)
4234 GstElement *element = NULL;
4237 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4238 player->pipeline->mainbin, NULL);
4240 /* setup source for gapless play */
4241 switch (player->profile.uri_type) {
4243 case MM_PLAYER_URI_TYPE_FILE:
4244 element = __mmplayer_gst_make_file_src(player);
4246 case MM_PLAYER_URI_TYPE_URL_HTTP:
4247 element = __mmplayer_gst_make_http_src(player);
4250 LOGE("not support uri type %d", player->profile.uri_type);
4255 LOGE("failed to create source element");
4264 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4267 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4268 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4270 SECURE_LOGD("uri : %s", player->profile.uri);
4272 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4274 if ((player->v_stream_caps) &&
4275 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4276 return MM_ERROR_PLAYER_INTERNAL;
4278 if ((player->a_stream_caps) &&
4279 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4280 return MM_ERROR_PLAYER_INTERNAL;
4282 if ((player->s_stream_caps) &&
4283 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4284 return MM_ERROR_PLAYER_INTERNAL;
4287 return MM_ERROR_NONE;
4291 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4293 mmplayer_gst_element_t *mainbin = NULL;
4294 GstElement *autoplug_elem = NULL;
4297 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4298 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4300 mainbin = player->pipeline->mainbin;
4302 LOGD("uri type %d", player->profile.uri_type);
4304 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4305 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4306 return MM_ERROR_PLAYER_INTERNAL;
4309 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4310 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4313 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4314 if (!autoplug_elem) {
4315 LOGE("failed to create uridecodebin3 element");
4319 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4320 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4321 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4323 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4324 LOGE("failed to add uridecodebin to pipeline");
4328 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4329 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4330 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4332 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4333 LOGE("failed to create fakesink");
4336 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4338 /* take ownership of fakesink. we are reusing it */
4339 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4341 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4342 LOGE("failed to add fakesink to bin");
4343 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4348 return MM_ERROR_NONE;
4352 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4353 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4355 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4356 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4358 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4359 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4361 return MM_ERROR_PLAYER_INTERNAL;
4365 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4367 mmplayer_gst_element_t *mainbin = NULL;
4368 GstElement *src_elem = NULL;
4369 GstElement *autoplug_elem = NULL;
4370 GList *element_bucket = NULL;
4371 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4374 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4375 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4377 LOGD("uri type %d", player->profile.uri_type);
4379 /* create source element */
4380 switch (player->profile.uri_type) {
4381 case MM_PLAYER_URI_TYPE_URL_RTSP:
4382 src_elem = __mmplayer_gst_make_rtsp_src(player);
4384 case MM_PLAYER_URI_TYPE_URL_HTTP:
4385 src_elem = __mmplayer_gst_make_http_src(player);
4387 case MM_PLAYER_URI_TYPE_FILE:
4388 src_elem = __mmplayer_gst_make_file_src(player);
4390 case MM_PLAYER_URI_TYPE_SS:
4392 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4393 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4395 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4399 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4400 LOGD("get timeout from ini");
4401 http_timeout = player->ini.http_timeout;
4404 /* setting property to streaming source */
4405 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4408 case MM_PLAYER_URI_TYPE_MEM:
4410 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4412 src_elem = gst_element_factory_make("appsrc", "mem-source");
4414 LOGE("failed to create appsrc element");
4418 g_object_set(src_elem, "stream-type", stream_type,
4419 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4421 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4422 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4423 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4424 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4428 LOGE("not support uri type");
4433 LOGE("failed to create source element");
4434 return MM_ERROR_PLAYER_INTERNAL;
4437 mainbin = player->pipeline->mainbin;
4439 /* take source element */
4440 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4442 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4443 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4444 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4446 /* create next element for auto-plugging */
4447 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4448 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4449 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4450 if (!autoplug_elem) {
4451 LOGE("failed to create typefind element");
4455 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4456 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4457 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4458 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4459 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4460 if (!autoplug_elem) {
4461 LOGE("failed to create decodebin");
4465 /* default size of mq in decodebin is 2M
4466 * but it can cause blocking issue during seeking depends on content. */
4467 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4470 if (autoplug_elem) {
4471 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4472 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4473 mainbin[autoplug_elem_id].gst = autoplug_elem;
4475 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4478 /* add elements to pipeline */
4479 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4480 LOGE("failed to add elements to pipeline");
4484 /* linking elements in the bucket by added order. */
4485 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4486 LOGE("failed to link some elements");
4490 /* FIXME: need to check whether this is required or not. */
4491 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4492 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4493 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4494 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4495 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4497 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4498 LOGE("failed to create fakesink");
4501 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4503 /* take ownership of fakesink. we are reusing it */
4504 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4506 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4507 LOGE("failed to add fakesink to bin");
4508 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4513 g_list_free(element_bucket);
4516 return MM_ERROR_NONE;
4519 g_list_free(element_bucket);
4521 if (mainbin[MMPLAYER_M_SRC].gst)
4522 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4524 if (mainbin[autoplug_elem_id].gst)
4525 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4527 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4528 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4530 mainbin[MMPLAYER_M_SRC].gst = NULL;
4531 mainbin[autoplug_elem_id].gst = NULL;
4532 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4534 return MM_ERROR_PLAYER_INTERNAL;
4538 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4541 mmplayer_gst_element_t *mainbin = NULL;
4544 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4545 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4547 mainbin = player->pipeline->mainbin;
4549 /* connect bus callback */
4550 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4552 LOGE("cannot get bus from pipeline");
4553 return MM_ERROR_PLAYER_INTERNAL;
4556 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4557 (GstBusFunc)__mmplayer_gst_msg_push, player,
4558 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4559 if (player->bus_watcher == 0) {
4560 LOGE("failed to add bus watch");
4561 return MM_ERROR_PLAYER_INTERNAL;
4564 g_mutex_init(&player->bus_watcher_mutex);
4565 g_cond_init(&player->bus_watcher_cond);
4567 player->context.thread_default = g_main_context_get_thread_default();
4568 if (player->context.thread_default == NULL) {
4569 player->context.thread_default = g_main_context_default();
4570 LOGD("thread-default context is the global default context");
4572 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4574 /* set sync handler to get tag synchronously */
4575 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4576 gst_object_unref(GST_OBJECT(bus));
4578 /* create gst bus_msb_cb thread */
4579 g_mutex_init(&player->bus_msg_thread_mutex);
4580 g_cond_init(&player->bus_msg_thread_cond);
4581 player->bus_msg_thread_exit = FALSE;
4582 player->bus_msg_thread =
4583 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4584 if (!player->bus_msg_thread) {
4585 LOGE("failed to create gst BUS msg thread");
4586 g_mutex_clear(&player->bus_msg_thread_mutex);
4587 g_cond_clear(&player->bus_msg_thread_cond);
4588 return MM_ERROR_PLAYER_INTERNAL;
4592 return MM_ERROR_NONE;
4596 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4598 int ret = MM_ERROR_NONE;
4599 mmplayer_gst_element_t *mainbin = NULL;
4600 MMMessageParamType msg_param = {0,};
4601 GstElement *element = NULL;
4602 MMHandleType attrs = 0;
4604 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4608 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4609 LOGE("player is not initialized");
4613 mainbin = player->pipeline->mainbin;
4614 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4616 attrs = MMPLAYER_GET_ATTRS(player);
4618 LOGE("fail to get attributes");
4622 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4624 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4625 LOGE("failed to parse profile");
4626 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4630 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4631 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4632 LOGE("dash or hls is not supportable");
4633 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4637 if (!MMPLAYER_USE_DECODEBIN(player)) {
4638 ret = _mmplayer_gst_build_pipeline_with_src(player);
4639 if (ret != MM_ERROR_NONE)
4642 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4643 LOGE("Failed to change state of uridecodebin3 element");
4649 element = _mmplayer_gst_create_source(player);
4651 LOGE("no source element was created");
4655 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4656 LOGE("failed to add source element to pipeline");
4657 gst_object_unref(GST_OBJECT(element));
4662 /* take source element */
4663 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4664 mainbin[MMPLAYER_M_SRC].gst = element;
4668 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4669 if (player->streamer == NULL) {
4670 player->streamer = _mm_player_streaming_create();
4671 _mm_player_streaming_initialize(player->streamer, TRUE);
4674 elem_idx = MMPLAYER_M_TYPEFIND;
4675 element = gst_element_factory_make("typefind", "typefinder");
4676 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4677 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4679 elem_idx = MMPLAYER_M_AUTOPLUG;
4680 element = _mmplayer_gst_make_decodebin(player);
4683 /* check autoplug element is OK */
4685 LOGE("can not create element(%d)", elem_idx);
4689 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4690 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4691 gst_object_unref(GST_OBJECT(element));
4696 mainbin[elem_idx].id = elem_idx;
4697 mainbin[elem_idx].gst = element;
4699 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4700 LOGE("Failed to link src - autoplug(or typefind)");
4704 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4705 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4706 LOGE("Failed to change state of src element");
4710 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4711 LOGE("Failed to change state of decodebin");
4716 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4717 LOGE("Failed to change state of src element");
4722 player->gapless.stream_changed = TRUE;
4723 player->gapless.running = TRUE;
4729 _mmplayer_set_reconfigure_state(player, FALSE);
4730 if (!player->msg_posted) {
4731 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4732 player->msg_posted = TRUE;