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 */
937 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
938 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
939 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
941 gint64 dur_bytes = 0L;
943 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
944 LOGE("fail to get duration.");
946 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
947 * use file information was already set on Q2 when it was created. */
948 _mm_player_streaming_set_queue2(player->streamer,
949 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
950 TRUE, /* use_buffering */
951 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
952 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
955 LOGD("GST_MESSAGE_STREAMS_SELECTED");
956 player->no_more_pad = TRUE;
957 _mmplayer_set_reconfigure_state(player, FALSE);
958 _mmplayer_pipeline_complete(NULL, player);
971 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
973 guint64 data_size = 0;
976 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
978 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
980 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
981 data_size = player->http_content_size;
984 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
985 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
991 __mmplayer_handle_buffering_playback(mmplayer_t *player)
993 int ret = MM_ERROR_NONE;
994 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
995 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
996 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
997 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
999 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1000 LOGW("do nothing for buffering msg");
1001 ret = MM_ERROR_PLAYER_INVALID_STATE;
1005 prev_state = MMPLAYER_PREV_STATE(player);
1006 current_state = MMPLAYER_CURRENT_STATE(player);
1007 target_state = MMPLAYER_TARGET_STATE(player);
1008 pending_state = MMPLAYER_PENDING_STATE(player);
1010 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1011 MMPLAYER_STATE_GET_NAME(prev_state),
1012 MMPLAYER_STATE_GET_NAME(current_state),
1013 MMPLAYER_STATE_GET_NAME(pending_state),
1014 MMPLAYER_STATE_GET_NAME(target_state),
1015 player->streamer->buffering_state);
1017 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1018 /* NOTE : if buffering has done, player has to go to target state. */
1019 switch (target_state) {
1020 case MM_PLAYER_STATE_PAUSED:
1022 switch (pending_state) {
1023 case MM_PLAYER_STATE_PLAYING:
1024 _mmplayer_gst_pause(player, TRUE);
1027 case MM_PLAYER_STATE_PAUSED:
1028 LOGD("player is already going to paused state, there is nothing to do.");
1031 case MM_PLAYER_STATE_NONE:
1032 case MM_PLAYER_STATE_NULL:
1033 case MM_PLAYER_STATE_READY:
1035 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1041 case MM_PLAYER_STATE_PLAYING:
1043 switch (pending_state) {
1044 case MM_PLAYER_STATE_NONE:
1046 if (current_state != MM_PLAYER_STATE_PLAYING)
1047 _mmplayer_gst_resume(player, TRUE);
1051 case MM_PLAYER_STATE_PAUSED:
1052 /* NOTE: It should be worked as asynchronously.
1053 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1055 if (current_state == MM_PLAYER_STATE_PLAYING) {
1056 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1057 * The current state should be changed to paused purposely to prevent state conflict.
1059 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1061 _mmplayer_gst_resume(player, TRUE);
1064 case MM_PLAYER_STATE_PLAYING:
1065 LOGD("player is already going to playing state, there is nothing to do.");
1068 case MM_PLAYER_STATE_NULL:
1069 case MM_PLAYER_STATE_READY:
1071 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1077 case MM_PLAYER_STATE_NULL:
1078 case MM_PLAYER_STATE_READY:
1079 case MM_PLAYER_STATE_NONE:
1081 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1085 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1086 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1088 switch (pending_state) {
1089 case MM_PLAYER_STATE_NONE:
1091 if (current_state != MM_PLAYER_STATE_PAUSED) {
1092 /* rtsp streaming pause makes rtsp server stop sending data. */
1093 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1094 LOGD("set pause state during buffering");
1095 _mmplayer_gst_pause(player, TRUE);
1101 case MM_PLAYER_STATE_PLAYING:
1102 /* rtsp streaming pause makes rtsp server stop sending data. */
1103 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1104 _mmplayer_gst_pause(player, TRUE);
1107 case MM_PLAYER_STATE_PAUSED:
1110 case MM_PLAYER_STATE_NULL:
1111 case MM_PLAYER_STATE_READY:
1113 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1122 static stream_variant_t *
1123 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1125 stream_variant_t *var_info = NULL;
1126 g_return_val_if_fail(self != NULL, NULL);
1128 var_info = g_new0(stream_variant_t, 1);
1129 if (!var_info) return NULL;
1130 var_info->bandwidth = self->bandwidth;
1131 var_info->width = self->width;
1132 var_info->height = self->height;
1137 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1143 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1144 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1146 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1147 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1148 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1150 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1151 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1152 player->http_content_size = (bytes > 0) ? bytes : 0;
1155 /* handling audio clip which has vbr. means duration is keep changing */
1156 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1165 __mmplayer_eos_timer_cb(gpointer u_data)
1167 mmplayer_t *player = NULL;
1168 MMHandleType attrs = 0;
1171 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1173 player = (mmplayer_t *)u_data;
1174 attrs = MMPLAYER_GET_ATTRS(player);
1176 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1180 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1181 if (ret_value != MM_ERROR_NONE)
1182 LOGE("seeking to 0 failed in repeat play");
1185 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1188 /* we are returning FALSE as we need only one posting */
1193 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1195 MMPLAYER_RETURN_IF_FAIL(player);
1197 /* post now if delay is zero */
1198 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1199 LOGD("eos delay is zero. posting EOS now");
1200 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1202 if (player->audio_decoded_cb)
1203 _mmplayer_cancel_eos_timer(player);
1208 /* cancel if existing */
1209 _mmplayer_cancel_eos_timer(player);
1211 /* init new timeout */
1212 /* NOTE : consider give high priority to this timer */
1213 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1215 player->eos_timer = g_timeout_add(delay_in_ms,
1216 __mmplayer_eos_timer_cb, player);
1218 player->context.global_default = g_main_context_default();
1219 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1221 /* check timer is valid. if not, send EOS now */
1222 if (player->eos_timer == 0) {
1223 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1224 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1229 __mmplayer_gst_pending_seek(mmplayer_t *player)
1231 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1232 int ret = MM_ERROR_NONE;
1236 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1238 if (!player->pending_seek.is_pending) {
1239 LOGD("pending seek is not reserved. nothing to do.");
1243 /* check player state if player could pending seek or not. */
1244 current_state = MMPLAYER_CURRENT_STATE(player);
1246 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1247 LOGW("try to pending seek in %s state, try next time. ",
1248 MMPLAYER_STATE_GET_NAME(current_state));
1252 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1254 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1255 if (ret != MM_ERROR_NONE)
1256 LOGE("failed to seek pending position. just keep staying current position.");
1258 player->pending_seek.is_pending = false;
1266 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1268 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1270 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1272 audiobin = player->pipeline->audiobin; /* can be null */
1273 videobin = player->pipeline->videobin; /* can be null */
1274 textbin = player->pipeline->textbin; /* can be null */
1276 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1278 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1279 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1281 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1282 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1284 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1285 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1291 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1293 mmplayer_gst_element_t *textbin;
1296 MMPLAYER_RETURN_IF_FAIL(player &&
1298 player->pipeline->textbin);
1300 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1302 textbin = player->pipeline->textbin;
1305 LOGD("Drop subtitle text after getting EOS");
1307 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1308 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1310 player->is_subtitle_force_drop = TRUE;
1312 if (player->is_subtitle_force_drop == TRUE) {
1313 LOGD("Enable subtitle data path without drop");
1315 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1316 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1318 LOGD("non-connected with external display");
1320 player->is_subtitle_force_drop = FALSE;
1326 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1328 MMHandleType attrs = 0;
1333 /* NOTE : EOS event is coming multiple time. watch out it */
1334 /* check state. we only process EOS when pipeline state goes to PLAYING */
1335 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1336 LOGD("EOS received on non-playing state. ignoring it");
1340 if (player->pipeline && player->pipeline->textbin)
1341 __mmplayer_drop_subtitle(player, TRUE);
1343 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1344 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1346 /* rewind if repeat count is greater then zero */
1347 /* get play count */
1348 attrs = MMPLAYER_GET_ATTRS(player);
1350 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1352 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1354 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1355 if (player->playback_rate < 0.0) {
1356 player->resumed_by_rewind = TRUE;
1357 _mmplayer_set_mute((MMHandleType)player, false);
1358 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1361 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1364 player->sent_bos = FALSE;
1366 LOGD("do not post eos msg for repeating");
1371 if (player->pipeline)
1372 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1374 /* post eos message to application */
1375 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1377 /* reset last position */
1378 player->last_position = 0;
1385 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1387 GError *error = NULL;
1388 gchar *debug = NULL;
1392 /* generating debug info before returning error */
1393 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1395 /* get error code */
1396 gst_message_parse_error(msg, &error, &debug);
1398 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1399 /* Note : the streaming error from the streaming source is handled
1400 * using __mmplayer_handle_streaming_error.
1402 __mmplayer_handle_streaming_error(player, msg, error);
1404 /* dump state of all element */
1405 _mmplayer_dump_pipeline_state(player);
1407 /* translate gst error code to msl error code. then post it
1408 * to application if needed
1410 __mmplayer_handle_gst_error(player, msg, error);
1413 LOGE("error debug : %s", debug);
1416 MMPLAYER_FREEIF(debug);
1417 g_error_free(error);
1424 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1426 MMMessageParamType msg_param = {0, };
1427 int bRet = MM_ERROR_NONE;
1430 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1432 if (!MMPLAYER_IS_STREAMING(player)) {
1433 LOGW("this is not streaming playback.");
1437 MMPLAYER_CMD_LOCK(player);
1439 if (!player->streamer) {
1440 LOGW("Pipeline is shutting down");
1441 MMPLAYER_CMD_UNLOCK(player);
1445 /* ignore the remained buffering message till getting 100% msg */
1446 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1447 gint buffer_percent = 0;
1449 gst_message_parse_buffering(msg, &buffer_percent);
1451 if (buffer_percent == MAX_BUFFER_PERCENT) {
1452 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1453 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1454 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1456 MMPLAYER_CMD_UNLOCK(player);
1460 /* ignore the remained buffering message */
1461 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1462 gint buffer_percent = 0;
1464 gst_message_parse_buffering(msg, &buffer_percent);
1466 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1467 player->streamer->buffering_percent, buffer_percent);
1469 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1470 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1471 player->streamer->buffering_req.is_pre_buffering = FALSE;
1473 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1475 LOGD("interrupted buffering - ignored the remained buffering msg!");
1476 MMPLAYER_CMD_UNLOCK(player);
1481 __mmplayer_update_buffer_setting(player, msg);
1483 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1485 if (bRet == MM_ERROR_NONE) {
1486 msg_param.connection.buffering = player->streamer->buffering_percent;
1487 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1489 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1490 player->pending_resume &&
1491 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1493 player->is_external_subtitle_added_now = FALSE;
1494 player->pending_resume = FALSE;
1495 _mmplayer_resume((MMHandleType)player);
1498 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1499 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1501 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1502 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1503 player->seek_state = MMPLAYER_SEEK_NONE;
1504 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1505 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1506 /* Considering the async state transition in case of RTSP.
1507 After getting state change gst msg, seek completed msg will be posted. */
1508 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1512 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1513 if (!player->streamer) {
1514 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1515 MMPLAYER_CMD_UNLOCK(player);
1519 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1521 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1522 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1524 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1525 msg_param.connection.buffering = player->streamer->buffering_percent;
1526 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1528 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1531 msg_param.connection.buffering = player->streamer->buffering_percent;
1532 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1535 MMPLAYER_CMD_UNLOCK(player);
1543 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1545 mmplayer_gst_element_t *mainbin;
1546 const GValue *voldstate, *vnewstate, *vpending;
1547 GstState oldstate = GST_STATE_NULL;
1548 GstState newstate = GST_STATE_NULL;
1549 GstState pending = GST_STATE_NULL;
1552 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1554 mainbin = player->pipeline->mainbin;
1556 /* we only handle messages from pipeline */
1557 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1560 /* get state info from msg */
1561 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1562 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1563 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1565 if (!voldstate || !vnewstate) {
1566 LOGE("received msg has wrong format.");
1570 oldstate = (GstState)voldstate->data[0].v_int;
1571 newstate = (GstState)vnewstate->data[0].v_int;
1573 pending = (GstState)vpending->data[0].v_int;
1575 LOGD("state changed [%s] : %s ---> %s final : %s",
1576 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1577 gst_element_state_get_name((GstState)oldstate),
1578 gst_element_state_get_name((GstState)newstate),
1579 gst_element_state_get_name((GstState)pending));
1581 if (newstate == GST_STATE_PLAYING) {
1582 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1584 int retVal = MM_ERROR_NONE;
1585 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1587 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1589 if (MM_ERROR_NONE != retVal)
1590 LOGE("failed to seek pending position. just keep staying current position.");
1592 player->pending_seek.is_pending = false;
1596 if (oldstate == newstate) {
1597 LOGD("pipeline reports state transition to old state");
1602 case GST_STATE_PAUSED:
1604 gboolean prepare_async = FALSE;
1606 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1607 // managed prepare async case
1608 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1609 LOGD("checking prepare mode for async transition - %d", prepare_async);
1612 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1613 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1615 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1616 _mm_player_streaming_set_content_bitrate(player->streamer,
1617 player->total_maximum_bitrate, player->total_bitrate);
1619 if (player->pending_seek.is_pending) {
1620 LOGW("trying to do pending seek");
1621 MMPLAYER_CMD_LOCK(player);
1622 __mmplayer_gst_pending_seek(player);
1623 MMPLAYER_CMD_UNLOCK(player);
1629 case GST_STATE_PLAYING:
1631 if (MMPLAYER_IS_STREAMING(player)) {
1632 // managed prepare async case when buffering is completed
1633 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1634 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1635 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1636 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1638 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1640 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1641 if (player->streamer->buffering_percent < 100) {
1643 MMMessageParamType msg_param = {0, };
1644 LOGW("Posting Buffering Completed Message to Application !!!");
1646 msg_param.connection.buffering = 100;
1647 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1652 if (player->gapless.stream_changed) {
1653 _mmplayer_update_content_attrs(player, ATTR_ALL);
1654 player->gapless.stream_changed = FALSE;
1657 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1658 player->seek_state = MMPLAYER_SEEK_NONE;
1659 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1663 case GST_STATE_VOID_PENDING:
1664 case GST_STATE_NULL:
1665 case GST_STATE_READY:
1675 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1677 const gchar *structure_name;
1678 gint count = 0, idx = 0;
1681 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1683 if (gst_message_get_structure(msg) == NULL)
1686 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1687 if (!structure_name)
1690 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1692 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1693 const GValue *var_info = NULL;
1695 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1696 if (var_info != NULL) {
1697 if (player->adaptive_info.var_list)
1698 g_list_free_full(player->adaptive_info.var_list, g_free);
1700 /* share addr or copy the list */
1701 player->adaptive_info.var_list =
1702 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1704 count = g_list_length(player->adaptive_info.var_list);
1706 stream_variant_t *temp = NULL;
1708 /* print out for debug */
1709 LOGD("num of variant_info %d", count);
1710 for (idx = 0; idx < count; idx++) {
1711 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1713 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1719 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1720 gint num_buffers = 0;
1721 gint extra_num_buffers = 0;
1723 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1724 LOGD("video_num_buffers : %d", num_buffers);
1725 mm_player_set_attribute((MMHandleType)player, NULL,
1726 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1729 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1730 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1731 mm_player_set_attribute((MMHandleType)player, NULL,
1732 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1737 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1738 _mmplayer_track_update_text_attr_info(player, msg);
1740 /* custom message */
1741 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1742 MMMessageParamType msg_param = {0,};
1743 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1744 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1747 /* custom message for RTSP attribute :
1748 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1749 sdp which has contents info is received when rtsp connection is opened.
1750 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1751 if (!strcmp(structure_name, "rtspsrc_properties")) {
1752 g_autofree gchar *audio_codec = NULL;
1753 g_autofree gchar *video_codec = NULL;
1754 g_autofree gchar *video_frame_size = NULL;
1756 gst_structure_get(gst_message_get_structure(msg),
1757 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1758 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1759 player->streaming_type = _mmplayer_get_stream_service_type(player);
1761 gst_structure_get(gst_message_get_structure(msg),
1762 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1763 LOGD("rtsp_audio_codec : %s", audio_codec);
1765 mm_player_set_attribute((MMHandleType)player, NULL,
1766 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1768 gst_structure_get(gst_message_get_structure(msg),
1769 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1770 LOGD("rtsp_video_codec : %s", video_codec);
1772 mm_player_set_attribute((MMHandleType)player, NULL,
1773 "content_video_codec", video_codec, strlen(video_codec), NULL);
1775 gst_structure_get(gst_message_get_structure(msg),
1776 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1777 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1778 if (video_frame_size) {
1779 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1780 mm_player_set_attribute((MMHandleType)player, NULL,
1781 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1782 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1784 g_strfreev(res_str);
1793 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1795 mmplayer_gst_element_t *mainbin;
1798 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1800 mainbin = player->pipeline->mainbin;
1802 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1804 /* we only handle messages from pipeline */
1805 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1808 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1809 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1810 player->seek_state = MMPLAYER_SEEK_NONE;
1811 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1812 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1813 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1814 LOGD("sync %s state(%s) with parent state(%s)",
1815 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1816 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1817 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1819 /* In case of streaming, pause is required before finishing seeking by buffering.
1820 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1821 Because the buffering state is controlled according to the state transition for force resume,
1822 the decodebin state should be paused as player state. */
1823 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1826 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1827 (player->streamer) &&
1828 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1829 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1830 GstQuery *query = NULL;
1831 gboolean busy = FALSE;
1834 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1835 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1836 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1837 gst_query_parse_buffering_percent(query, &busy, &percent);
1838 gst_query_unref(query);
1840 LOGD("buffered percent(%s): %d",
1841 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1845 __mmplayer_handle_buffering_playback(player);
1848 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1858 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1860 GValue val = { 0, };
1862 guint indent = GPOINTER_TO_UINT(user_data);
1864 if (!gst_tag_list_copy_value(&val, tags, tag))
1867 if (G_VALUE_HOLDS_STRING(&val))
1868 str = g_value_dup_string(&val);
1870 str = gst_value_serialize(&val);
1872 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1874 g_value_unset(&val);
1879 __mmplayer_dump_collection(GstStreamCollection * collection)
1883 GstTagList *tags = NULL;
1885 GstCaps *caps = NULL;
1887 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1888 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1889 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1890 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1891 gst_stream_get_stream_flags(stream));
1892 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1894 caps = gst_stream_get_caps(stream);
1896 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1897 gst_caps_unref(caps);
1901 tags = gst_stream_get_tags(stream);
1904 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1905 gst_tag_list_unref(tags);
1912 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1913 GstStream *stream, GParamSpec *pspec, gpointer data)
1915 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1916 gst_stream_get_stream_id(stream), pspec->name, collection);
1917 if (g_str_equal(pspec->name, "caps")) {
1918 GstCaps *caps = gst_stream_get_caps(stream);
1919 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1920 gst_caps_unref(caps);
1924 if (g_str_equal (pspec->name, "tags")) {
1925 GstTagList *tags = gst_stream_get_tags(stream);
1928 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1929 gst_tag_list_unref(tags);
1936 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1938 mmplayer_t *player = (mmplayer_t *)(data);
1940 MMPLAYER_RETURN_IF_FAIL(player);
1941 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1943 switch (GST_MESSAGE_TYPE(msg)) {
1944 case GST_MESSAGE_UNKNOWN:
1945 LOGD("unknown message received");
1948 case GST_MESSAGE_EOS:
1949 LOGD("GST_MESSAGE_EOS received");
1950 __mmplayer_gst_handle_eos_message(player, msg);
1953 case GST_MESSAGE_ERROR:
1954 _mmplayer_set_reconfigure_state(player, FALSE);
1955 __mmplayer_gst_handle_error_message(player, msg);
1958 case GST_MESSAGE_WARNING:
1961 GError *error = NULL;
1963 gst_message_parse_warning(msg, &error, &debug);
1965 LOGD("warning : %s", error->message);
1966 LOGD("debug : %s", debug);
1968 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1970 MMPLAYER_FREEIF(debug);
1971 g_error_free(error);
1975 case GST_MESSAGE_TAG:
1977 LOGD("GST_MESSAGE_TAG");
1978 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1979 LOGW("failed to extract tags from gstmessage");
1983 case GST_MESSAGE_BUFFERING:
1984 __mmplayer_gst_handle_buffering_message(player, msg);
1987 case GST_MESSAGE_STATE_CHANGED:
1988 __mmplayer_gst_handle_state_message(player, msg);
1991 case GST_MESSAGE_CLOCK_LOST:
1993 GstClock *clock = NULL;
1994 gboolean need_new_clock = FALSE;
1996 gst_message_parse_clock_lost(msg, &clock);
1997 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1999 if (!player->videodec_linked)
2000 need_new_clock = TRUE;
2001 else if (!player->ini.use_system_clock)
2002 need_new_clock = TRUE;
2004 if (need_new_clock) {
2005 LOGD("Provide clock is TRUE, do pause->resume");
2006 _mmplayer_gst_pause(player, FALSE);
2007 _mmplayer_gst_resume(player, FALSE);
2012 case GST_MESSAGE_NEW_CLOCK:
2014 GstClock *clock = NULL;
2015 gst_message_parse_new_clock(msg, &clock);
2016 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2020 case GST_MESSAGE_ELEMENT:
2021 __mmplayer_gst_handle_element_message(player, msg);
2024 case GST_MESSAGE_DURATION_CHANGED:
2026 LOGD("GST_MESSAGE_DURATION_CHANGED");
2027 if (!__mmplayer_gst_handle_duration(player, msg))
2028 LOGW("failed to update duration");
2032 case GST_MESSAGE_ASYNC_START:
2033 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2036 case GST_MESSAGE_ASYNC_DONE:
2037 __mmplayer_gst_handle_async_done_message(player, msg);
2039 case GST_MESSAGE_STREAM_COLLECTION:
2041 GstStreamCollection *collection = NULL;
2042 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2044 gst_message_parse_stream_collection(msg, &collection);
2046 __mmplayer_dump_collection(collection);
2047 if (player->collection && player->stream_notify_id) {
2048 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2049 player->stream_notify_id = 0;
2051 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2052 if (player->collection) {
2053 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2054 (GCallback)__mmplayer_stream_notify_cb, player);
2056 gst_object_unref(collection);
2059 case GST_MESSAGE_STREAMS_SELECTED:
2061 GstStreamCollection *collection = NULL;
2062 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2064 gst_message_parse_streams_selected(msg, &collection);
2066 guint i = 0, len = 0;
2067 len = gst_message_streams_selected_get_size(msg);
2068 for (i = 0; i < len; i++) {
2069 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2070 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2071 gst_object_unref(stream);
2073 gst_object_unref (collection);
2078 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2079 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2080 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2081 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2082 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2083 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2084 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2085 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2086 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2087 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2088 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2089 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2090 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2091 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2092 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2099 /* should not call 'gst_message_unref(msg)' */
2103 static GstBusSyncReply
2104 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2106 mmplayer_t *player = (mmplayer_t *)data;
2107 GstBusSyncReply reply = GST_BUS_DROP;
2109 if (!(player->pipeline && player->pipeline->mainbin)) {
2110 LOGE("player pipeline handle is null");
2111 return GST_BUS_PASS;
2114 if (!__mmplayer_gst_check_useful_message(player, message)) {
2115 gst_message_unref(message);
2116 return GST_BUS_DROP;
2119 switch (GST_MESSAGE_TYPE(message)) {
2120 case GST_MESSAGE_TAG:
2121 __mmplayer_gst_extract_tag_from_msg(player, message);
2125 GstTagList *tags = NULL;
2127 gst_message_parse_tag(message, &tags);
2129 LOGE("TAGS received from element \"%s\".",
2130 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2132 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2133 gst_tag_list_unref(tags);
2141 case GST_MESSAGE_DURATION_CHANGED:
2142 __mmplayer_gst_handle_duration(player, message);
2144 case GST_MESSAGE_ELEMENT:
2146 const gchar *klass = NULL;
2147 klass = gst_element_factory_get_metadata
2148 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2149 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2150 reply = GST_BUS_PASS;
2153 __mmplayer_gst_handle_element_message(player, message);
2156 case GST_MESSAGE_ASYNC_DONE:
2157 /* NOTE:Don't call gst_callback directly
2158 * because previous frame can be showed even though this message is received for seek.
2161 reply = GST_BUS_PASS;
2165 if (reply == GST_BUS_DROP)
2166 gst_message_unref(message);
2172 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2174 GstElement *appsrc = element;
2175 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2176 GstBuffer *buffer = NULL;
2177 GstFlowReturn ret = GST_FLOW_OK;
2180 MMPLAYER_RETURN_IF_FAIL(element);
2181 MMPLAYER_RETURN_IF_FAIL(buf);
2183 buffer = gst_buffer_new();
2185 if (buf->offset < 0 || buf->len < 0) {
2186 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2190 if (buf->offset >= buf->len) {
2191 LOGD("call eos appsrc");
2192 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2196 if (buf->len - buf->offset < size)
2197 len = buf->len - buf->offset;
2199 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2200 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2201 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2204 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2206 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2212 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2214 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2216 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2218 buf->offset = (int)size;
2224 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2226 mmplayer_t *player = (mmplayer_t *)user_data;
2227 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2228 MMMessageParamType msg_param = {0,};
2229 guint64 current_level_bytes = 0;
2231 MMPLAYER_RETURN_IF_FAIL(player);
2233 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2234 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2235 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2236 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2238 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2242 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2244 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2246 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2247 msg_param.buffer_status.stream_type = stream_type;
2248 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2249 msg_param.buffer_status.bytes = current_level_bytes;
2251 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2255 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2257 mmplayer_t *player = (mmplayer_t *)user_data;
2258 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2259 MMMessageParamType msg_param = {0,};
2260 guint64 current_level_bytes = 0;
2262 MMPLAYER_RETURN_IF_FAIL(player);
2264 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2265 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2266 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2267 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2269 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2273 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2275 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2277 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2278 msg_param.buffer_status.stream_type = stream_type;
2279 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2280 msg_param.buffer_status.bytes = current_level_bytes;
2282 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2286 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2288 mmplayer_t *player = (mmplayer_t *)user_data;
2289 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2290 MMMessageParamType msg_param = {0,};
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2294 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2295 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2296 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2297 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2299 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2303 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2305 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2306 msg_param.seek_data.stream_type = stream_type;
2307 msg_param.seek_data.offset = position;
2309 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2315 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2317 #define MAX_LEN_NAME 20
2319 gboolean ret = FALSE;
2320 GstPad *sinkpad = NULL;
2321 gchar *prefix = NULL;
2322 gchar dec_name[MAX_LEN_NAME] = {0, };
2323 main_element_id_e elem_id = MMPLAYER_M_NUM;
2325 mmplayer_gst_element_t *mainbin = NULL;
2326 GstElement *decodebin = NULL;
2327 GstCaps *dec_caps = NULL;
2331 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2333 player->pipeline->mainbin, FALSE);
2334 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2336 mainbin = player->pipeline->mainbin;
2338 case MM_PLAYER_STREAM_TYPE_AUDIO:
2340 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2342 case MM_PLAYER_STREAM_TYPE_VIDEO:
2344 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2347 LOGE("invalid type %d", type);
2351 if (mainbin[elem_id].gst) {
2352 LOGE("elem(%d) is already created", elem_id);
2356 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2358 /* create decodebin */
2359 decodebin = gst_element_factory_make("decodebin", dec_name);
2361 LOGE("failed to create %s", dec_name);
2365 /* raw pad handling signal */
2366 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2367 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2369 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2370 before looking for any elements that can handle that stream.*/
2371 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2372 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2374 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2375 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2376 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2378 /* This signal is emitted when a element is added to the bin.*/
2379 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2380 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2382 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2383 LOGE("failed to add new decodebin");
2387 dec_caps = gst_pad_query_caps(srcpad, NULL);
2390 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2392 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2393 gst_caps_unref(dec_caps);
2396 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2398 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2399 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2402 gst_object_unref(GST_OBJECT(sinkpad));
2404 gst_element_sync_state_with_parent(decodebin);
2406 mainbin[elem_id].id = elem_id;
2407 mainbin[elem_id].gst = decodebin;
2414 gst_object_unref(GST_OBJECT(sinkpad));
2417 gst_element_set_state(decodebin, GST_STATE_NULL);
2418 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2419 gst_object_unref(decodebin);
2427 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2429 #define MAX_LEN_NAME 20
2430 mmplayer_gst_element_t *mainbin = NULL;
2431 gchar *prefix = NULL;
2432 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2434 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2435 GstElement *src = NULL, *queue = NULL;
2436 GstPad *srcpad = NULL;
2439 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2440 player->pipeline->mainbin, FALSE);
2442 mainbin = player->pipeline->mainbin;
2444 LOGD("type(%d) path is creating", type);
2446 case MM_PLAYER_STREAM_TYPE_AUDIO:
2448 if (mainbin[MMPLAYER_M_SRC].gst)
2449 src_id = MMPLAYER_M_2ND_SRC;
2451 src_id = MMPLAYER_M_SRC;
2452 queue_id = MMPLAYER_M_A_BUFFER;
2454 case MM_PLAYER_STREAM_TYPE_VIDEO:
2456 src_id = MMPLAYER_M_SRC;
2457 queue_id = MMPLAYER_M_V_BUFFER;
2459 case MM_PLAYER_STREAM_TYPE_TEXT:
2460 prefix = "subtitle";
2461 src_id = MMPLAYER_M_SUBSRC;
2462 queue_id = MMPLAYER_M_S_BUFFER;
2465 LOGE("invalid type %d", type);
2469 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2470 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2473 src = gst_element_factory_make("appsrc", src_name);
2475 LOGF("failed to create %s", src_name);
2479 mainbin[src_id].id = src_id;
2480 mainbin[src_id].gst = src;
2482 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2483 "caps", caps, NULL);
2485 /* size of many video frames are larger than default blocksize as 4096 */
2486 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2487 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2489 if (player->media_stream_buffer_max_size[type] > 0)
2490 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2492 if (player->media_stream_buffer_min_percent[type] > 0)
2493 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2495 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2496 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2498 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2499 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2500 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2501 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2502 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2503 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2506 queue = gst_element_factory_make("queue2", queue_name);
2508 LOGE("failed to create %s", queue_name);
2511 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2513 mainbin[queue_id].id = queue_id;
2514 mainbin[queue_id].gst = queue;
2516 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2517 LOGE("failed to add src");
2521 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2522 LOGE("failed to add queue");
2526 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2527 LOGE("failed to link src and queue");
2531 /* create decoder */
2532 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2534 LOGE("failed to get srcpad of queue");
2538 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2539 _mmplayer_gst_create_decoder(player, srcpad, caps);
2541 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2542 LOGE("failed to create decoder");
2543 gst_object_unref(GST_OBJECT(srcpad));
2547 gst_object_unref(GST_OBJECT(srcpad));
2551 if (mainbin[src_id].gst) {
2552 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2553 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2554 gst_object_unref(mainbin[src_id].gst);
2555 mainbin[src_id].gst = NULL;
2558 if (mainbin[queue_id].gst) {
2559 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2560 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2561 gst_object_unref(mainbin[queue_id].gst);
2562 mainbin[queue_id].gst = NULL;
2569 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2571 GstPad *sinkpad = NULL;
2572 GstCaps *caps = NULL;
2573 GstElement *new_element = NULL;
2574 GstStructure *str = NULL;
2575 const gchar *name = NULL;
2577 mmplayer_t *player = (mmplayer_t *)data;
2581 MMPLAYER_RETURN_IF_FAIL(element && pad);
2582 MMPLAYER_RETURN_IF_FAIL(player &&
2584 player->pipeline->mainbin);
2586 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2587 * num_dynamic_pad will decreased after creating a sinkbin.
2589 player->num_dynamic_pad++;
2590 LOGD("stream count inc : %d", player->num_dynamic_pad);
2592 caps = gst_pad_query_caps(pad, NULL);
2593 MMPLAYER_CHECK_NULL(caps);
2595 str = gst_caps_get_structure(caps, 0);
2596 name = gst_structure_get_string(str, "media");
2598 LOGE("cannot get mimetype from structure.");
2602 if (strstr(name, "video")) {
2604 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2606 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2607 if (player->v_stream_caps) {
2608 gst_caps_unref(player->v_stream_caps);
2609 player->v_stream_caps = NULL;
2612 new_element = gst_element_factory_make("fakesink", NULL);
2613 player->num_dynamic_pad--;
2618 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2619 LOGE("failed to autoplug for caps");
2623 gst_caps_unref(caps);
2628 /* execute new_element if created*/
2630 LOGD("adding new element to pipeline");
2632 /* set state to READY before add to bin */
2633 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2635 /* add new element to the pipeline */
2636 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2637 LOGE("failed to add autoplug element to bin");
2641 /* get pad from element */
2642 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2644 LOGE("failed to get sinkpad from autoplug element");
2649 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2650 LOGE("failed to link autoplug element");
2654 gst_object_unref(sinkpad);
2657 /* run. setting PLAYING here since streaming source is live source */
2658 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2662 gst_caps_unref(caps);
2668 STATE_CHANGE_FAILED:
2670 /* FIXIT : take care if new_element has already added to pipeline */
2672 gst_object_unref(GST_OBJECT(new_element));
2675 gst_object_unref(GST_OBJECT(sinkpad));
2678 gst_caps_unref(caps);
2680 /* FIXIT : how to inform this error to MSL ????? */
2681 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2682 * then post an error to application
2687 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2689 mmplayer_t *player = (mmplayer_t *)data;
2693 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2694 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2695 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2696 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2698 * [1] audio and video will be dumped with filesink.
2699 * [2] autoplugging is done by just using pad caps.
2700 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2701 * and the video will be dumped via filesink.
2703 if (player->num_dynamic_pad == 0) {
2704 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2706 if (!_mmplayer_gst_remove_fakesink(player,
2707 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2708 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2709 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2710 * source element are not same. To overcome this situation, this function will called
2711 * several places and several times. Therefore, this is not an error case.
2716 /* create dot before error-return. for debugging */
2717 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2719 player->no_more_pad = TRUE;
2725 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2727 GstElement *element = NULL;
2728 gchar *user_agent = NULL;
2729 MMHandleType attrs = 0;
2732 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2734 /* get profile attribute */
2735 attrs = MMPLAYER_GET_ATTRS(player);
2737 LOGE("failed to get content attribute");
2741 element = gst_element_factory_make("rtspsrc", "rtsp source");
2743 LOGE("failed to create rtspsrc element");
2748 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2750 SECURE_LOGD("user_agent : %s", user_agent);
2752 /* setting property to streaming source */
2753 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2755 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2757 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2758 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2759 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2760 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2766 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2768 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2770 mmplayer_t *player = (mmplayer_t *)data;
2771 MMHandleType attrs = 0;
2772 gchar *user_agent, *cookies, **cookie_list;
2773 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2774 user_agent = cookies = NULL;
2778 MMPLAYER_RETURN_IF_FAIL(player);
2780 LOGD("source element %s", GST_ELEMENT_NAME(source));
2782 attrs = MMPLAYER_GET_ATTRS(player);
2784 LOGE("failed to get content attribute");
2788 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2789 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2791 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2792 http_timeout = player->ini.http_timeout;
2794 SECURE_LOGD("cookies : %s", cookies);
2795 SECURE_LOGD("user_agent : %s", user_agent);
2796 LOGD("timeout : %d", http_timeout);
2798 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2800 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2801 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2802 g_strfreev(cookie_list);
2806 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2812 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2814 mmplayer_t *player = (mmplayer_t *)data;
2815 gchar *user_agent = NULL;
2816 MMHandleType attrs = 0;
2819 MMPLAYER_RETURN_IF_FAIL(player);
2821 attrs = MMPLAYER_GET_ATTRS(player);
2823 LOGE("failed to get content attribute");
2827 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2829 SECURE_LOGD("user_agent : %s", user_agent);
2832 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2838 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2840 mmplayer_t *player = (mmplayer_t *)data;
2841 GstElement *source = NULL;
2844 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2846 g_object_get(orig, pspec->name, &source, NULL);
2848 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2849 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2851 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2852 __mmplayer_http_src_setup(source, data);
2853 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2854 __mmplayer_rtsp_src_setup(source, data);
2855 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2856 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2857 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2858 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2859 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2861 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2862 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2863 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2864 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2866 gst_object_unref (source);
2872 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
2874 const gchar *stream1_id = gst_stream_get_stream_id((GstStream *)stream1);
2875 const gchar *stream2_id = gst_stream_get_stream_id((GstStream *)stream2);
2877 return (g_strcmp0(stream1_id, stream2_id) == 0);
2881 __mmplayer_has_duplicated_stream(mmplayer_t *player, GstStreamType stype, GstStream *stream)
2883 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2885 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2888 case GST_STREAM_TYPE_AUDIO:
2889 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2891 case GST_STREAM_TYPE_VIDEO:
2892 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2894 case GST_STREAM_TYPE_TEXT:
2895 type = MM_PLAYER_TRACK_TYPE_TEXT;
2898 LOGD("Skip not supported stream stype");
2902 return g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL);
2906 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2907 GstStream * stream, gpointer data)
2909 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2910 GstStreamType stype = gst_stream_get_stream_type(stream);
2911 mmplayer_t *player = (mmplayer_t *)data;
2912 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2913 GstCaps *caps = gst_stream_get_caps(stream);
2914 GstStructure *caps_structure = NULL;
2915 gchar *caps_str = NULL;
2917 LOGD("Stream type %s flags 0x%x",
2918 gst_stream_type_get_name(stype),
2919 gst_stream_get_stream_flags(stream));
2920 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2922 if (__mmplayer_has_duplicated_stream(player, stype, stream)) {
2923 LOGD("Already added stream, skip it");
2929 caps_str = gst_caps_to_string(caps);
2930 caps_structure = gst_caps_get_structure(caps, 0);
2931 const gchar *mime = gst_structure_get_name(caps_structure);
2933 LOGD(" caps: %s", caps_str);
2935 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2936 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2937 LOGW("skip [%s] by unsupported codec keyword [%s]",
2938 mime, player->ini.unsupported_codec_keyword[idx]);
2940 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2948 case GST_STREAM_TYPE_AUDIO:
2950 gint samplerate = 0;
2953 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2955 if (caps_structure) {
2956 gst_structure_get_int(caps_structure, "rate", &samplerate);
2957 gst_structure_get_int(caps_structure, "channels", &channels);
2959 if (channels > 0 && samplerate == 0) {
2960 LOGW("Skip corrupted audio stream");
2964 if (g_strrstr(caps_str, "mobile-xmf"))
2965 mm_player_set_attribute((MMHandleType)player, NULL,
2966 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2970 case GST_STREAM_TYPE_VIDEO:
2975 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2977 /* do not support multi track video */
2978 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2981 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2983 /* don't make video because of not required */
2984 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2985 (!player->set_mode.video_export)) {
2986 LOGD("no need video decoding, skip video stream");
2990 if (caps_structure) {
2991 gst_structure_get_int(caps_structure, "width", &width);
2994 if (player->v_stream_caps) {
2995 gst_caps_unref(player->v_stream_caps);
2996 player->v_stream_caps = NULL;
2999 player->v_stream_caps = gst_caps_copy(caps);
3000 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3005 case GST_STREAM_TYPE_TEXT:
3006 type = MM_PLAYER_TRACK_TYPE_TEXT;
3009 LOGW("Skip not supported stream type");
3013 _mmplayer_track_update_stream(player, type, stream);
3015 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3016 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3017 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3018 _mmplayer_set_audio_attrs(player, caps);
3025 gst_caps_unref(caps);
3027 LOGD("ret %d", ret);
3032 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3033 GstStream * stream, gpointer data)
3035 mmplayer_t *player = (mmplayer_t *)data;
3036 GstStreamType stype = gst_stream_get_stream_type(stream);
3039 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3041 LOGD("stream type %s", gst_stream_type_get_name(stype));
3043 /* public does not support audio hw decoder at the moment */
3045 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3046 LOGW("video decoder resource is already acquired, skip it.");
3050 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3051 LOGE("failed to acquire video decoder resource");
3054 player->interrupted_by_resource = FALSE;
3060 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3062 GstIterator *iter = NULL;
3063 GValue item = {0, };
3064 GstElement *ch_element = NULL;
3065 GstElementFactory *ch_factory = NULL;
3068 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3070 iter = gst_bin_iterate_recurse(bin);
3071 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3073 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3074 ch_element = g_value_get_object(&item);
3075 ch_factory = gst_element_get_factory(ch_element);
3076 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3077 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3078 LOGD("Find %s element", element_name);
3082 g_value_reset(&item);
3084 gst_iterator_free(iter);
3090 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3092 mmplayer_t *player = (mmplayer_t *)data;
3094 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3096 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3097 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3098 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3100 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3101 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3102 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3105 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3107 mmplayer_t *player = (mmplayer_t *)data;
3108 int video_codec_type = 0;
3109 int audio_codec_type = 0;
3111 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3113 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3114 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3116 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3118 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3119 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3120 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3121 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3123 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3124 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3128 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3130 gchar *factory_name = NULL;
3131 mmplayer_t *player = (mmplayer_t *)data;
3134 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3136 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3138 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3140 if (g_strrstr(factory_name, "urisourcebin")) {
3141 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3143 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3145 LOGW("failed to find decodebin3");
3146 } else if (g_strrstr(factory_name, "parsebin")) {
3147 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3148 __mmplayer_parsebin_setup(GST_BIN(element), data);
3150 _mmplayer_gst_element_added(child, element, data);
3155 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3159 MMPLAYER_RETURN_IF_FAIL(player);
3160 MMPLAYER_RETURN_IF_FAIL(removed_element);
3162 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3164 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3165 GList *node = player->signals[type];
3167 GList *next_node = node->next;
3168 mmplayer_signal_item_t *item = node->data;
3169 if (item && item->obj == G_OBJECT(removed_element)) {
3170 player->signals[type] = g_list_delete_link(player->signals[type], node);
3171 MMPLAYER_FREEIF(item);
3181 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3183 mmplayer_t *player = (mmplayer_t *)data;
3187 MMPLAYER_RETURN_IF_FAIL(player);
3189 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3191 __mmplayer_delete_signal_connection(player, element);
3197 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3199 GstElement *uridecodebin3 = NULL;
3202 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3204 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3205 if (!uridecodebin3) {
3206 LOGE("failed to create uridecodebin3");
3211 SECURE_LOGD("uri : %s", player->profile.uri);
3213 /* setting property to streaming source */
3214 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3215 "message-forward", TRUE,
3216 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3217 "use-buffering", TRUE, NULL);
3219 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3220 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3222 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3223 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3225 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3226 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3228 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3229 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3231 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3232 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3234 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3235 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3237 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3238 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3240 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3241 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3243 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3244 LOGW("[DASH] this is still experimental feature");
3247 return uridecodebin3;
3251 __mmplayer_gst_make_http_src(mmplayer_t *player)
3253 #define MAX_RETRY_COUNT 10
3254 GstElement *element = NULL;
3255 MMHandleType attrs = 0;
3256 gchar *user_agent, *cookies, **cookie_list;
3257 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3259 user_agent = cookies = NULL;
3263 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3265 /* get profile attribute */
3266 attrs = MMPLAYER_GET_ATTRS(player);
3268 LOGE("failed to get content attribute");
3272 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3274 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3276 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3281 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3282 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3284 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3285 http_timeout = player->ini.http_timeout;
3288 SECURE_LOGD("location : %s", player->profile.uri);
3289 SECURE_LOGD("cookies : %s", cookies);
3290 SECURE_LOGD("user_agent : %s", user_agent);
3291 LOGD("timeout : %d", http_timeout);
3293 /* setting property to streaming source */
3294 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3295 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3296 "retries", MAX_RETRY_COUNT, NULL);
3298 /* parsing cookies */
3299 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3300 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3301 g_strfreev(cookie_list);
3305 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3307 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3308 LOGW("[DASH] this is still experimental feature");
3315 __mmplayer_gst_make_file_src(mmplayer_t *player)
3317 GstElement *element = NULL;
3320 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3322 LOGD("using filesrc for 'file://' handler");
3323 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3324 LOGE("failed to get storage info");
3328 element = gst_element_factory_make("filesrc", "source");
3330 LOGE("failed to create filesrc");
3334 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3341 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3343 mmplayer_t *player = (mmplayer_t *)data;
3345 g_return_val_if_fail(player, FALSE);
3346 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3347 gst_message_ref(msg);
3349 g_mutex_lock(&player->bus_msg_q_lock);
3350 g_queue_push_tail(player->bus_msg_q, msg);
3351 g_mutex_unlock(&player->bus_msg_q_lock);
3353 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3354 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3355 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3359 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3361 mmplayer_t *player = (mmplayer_t *)(data);
3362 GstMessage *msg = NULL;
3365 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3367 player->pipeline->mainbin &&
3368 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3371 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3373 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3374 while (!player->bus_msg_thread_exit) {
3375 g_mutex_lock(&player->bus_msg_q_lock);
3376 msg = g_queue_pop_head(player->bus_msg_q);
3377 g_mutex_unlock(&player->bus_msg_q_lock);
3379 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3382 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3383 /* handle the gst msg */
3384 __mmplayer_gst_bus_msg_callback(msg, player);
3385 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3386 gst_message_unref(msg);
3389 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3396 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3398 gint64 dur_nsec = 0;
3399 gint64 pos_nsec = 0;
3402 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3404 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3405 return MM_ERROR_NONE;
3407 /* NOTE : duration cannot be zero except live streaming.
3408 * Since some element could have some timing problem with querying duration, try again.
3410 if (player->duration == 0) {
3411 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3412 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3413 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3414 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3415 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3416 player->pending_seek.is_pending = true;
3417 player->pending_seek.pos = position;
3418 player->seek_state = MMPLAYER_SEEK_NONE;
3419 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3420 return MM_ERROR_PLAYER_NO_OP;
3422 player->seek_state = MMPLAYER_SEEK_NONE;
3423 return MM_ERROR_PLAYER_SEEK;
3426 player->duration = dur_nsec;
3429 if (player->duration > 0 && player->duration < position) {
3430 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3431 return MM_ERROR_INVALID_ARGUMENT;
3434 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3435 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3436 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3437 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3438 player->seek_state = MMPLAYER_SEEK_NONE;
3439 return MM_ERROR_PLAYER_NO_OP;
3444 return MM_ERROR_NONE;
3448 __mmplayer_gst_check_seekable(mmplayer_t *player)
3450 GstQuery *query = NULL;
3451 gboolean seekable = FALSE;
3453 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3457 query = gst_query_new_seeking(GST_FORMAT_TIME);
3458 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3459 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3460 gst_query_unref(query);
3463 LOGW("non-seekable content");
3464 player->seek_state = MMPLAYER_SEEK_NONE;
3468 LOGW("failed to get seeking query");
3469 gst_query_unref(query); /* keep seeking operation */
3476 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3478 GstState element_state = GST_STATE_VOID_PENDING;
3479 GstState element_pending_state = GST_STATE_VOID_PENDING;
3480 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3485 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3487 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3490 ret = gst_element_set_state(element, state);
3491 if (ret == GST_STATE_CHANGE_FAILURE) {
3492 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3494 /* dump state of all element */
3495 _mmplayer_dump_pipeline_state(player);
3497 return MM_ERROR_PLAYER_INTERNAL;
3500 /* return here so state transition to be done in async mode */
3502 LOGD("async state transition. not waiting for state complete.");
3503 return MM_ERROR_NONE;
3506 /* wait for state transition */
3507 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3508 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3509 LOGE("failed to change [%s] element state to [%s] within %d sec",
3510 GST_ELEMENT_NAME(element),
3511 gst_element_state_get_name(state), timeout);
3513 LOGE(" [%s] state : %s pending : %s",
3514 GST_ELEMENT_NAME(element),
3515 gst_element_state_get_name(element_state),
3516 gst_element_state_get_name(element_pending_state));
3518 /* dump state of all element */
3519 _mmplayer_dump_pipeline_state(player);
3521 return MM_ERROR_PLAYER_INTERNAL;
3524 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3528 return MM_ERROR_NONE;
3532 _mmplayer_gst_start(mmplayer_t *player)
3534 int ret = MM_ERROR_NONE;
3535 gboolean async = FALSE;
3539 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3541 /* NOTE : if SetPosition was called before Start. do it now
3542 * streaming doesn't support it. so it should be always sync
3543 * !!create one more api to check if there is pending seek rather than checking variables
3545 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3546 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3547 ret = _mmplayer_gst_pause(player, FALSE);
3548 if (ret != MM_ERROR_NONE) {
3549 LOGE("failed to set state to PAUSED for pending seek");
3553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3554 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3555 LOGW("failed to seek pending position. starting from the begin of content");
3558 LOGD("current state before doing transition");
3559 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3560 MMPLAYER_PRINT_STATE(player);
3562 /* set pipeline state to PLAYING */
3563 ret = _mmplayer_gst_set_state(player,
3564 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3565 if (ret != MM_ERROR_NONE) {
3566 LOGE("failed to set state to PLAYING");
3570 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3572 /* generating debug info before returning error */
3573 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3581 _mmplayer_gst_stop(mmplayer_t *player)
3583 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3584 MMHandleType attrs = 0;
3585 gboolean rewind = FALSE;
3587 int ret = MM_ERROR_NONE;
3591 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3592 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3594 LOGD("current state before doing transition");
3595 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3596 MMPLAYER_PRINT_STATE(player);
3598 attrs = MMPLAYER_GET_ATTRS(player);
3600 LOGE("cannot get content attribute");
3601 return MM_ERROR_PLAYER_INTERNAL;
3604 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3605 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3607 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3608 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3611 if (player->es_player_push_mode)
3612 /* disable the async state transition because there could be no data in the pipeline */
3613 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3616 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3618 if (player->es_player_push_mode) {
3619 /* enable the async state transition as default operation */
3620 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3623 /* return if set_state has failed */
3624 if (ret != MM_ERROR_NONE) {
3625 LOGE("failed to set state.");
3631 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3632 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3633 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3634 LOGW("failed to rewind");
3635 ret = MM_ERROR_PLAYER_SEEK;
3640 player->sent_bos = FALSE;
3642 if (player->es_player_push_mode) //for cloudgame
3645 /* wait for seek to complete */
3646 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3647 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3648 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3650 LOGE("fail to stop player.");
3651 ret = MM_ERROR_PLAYER_INTERNAL;
3652 _mmplayer_dump_pipeline_state(player);
3655 /* generate dot file if enabled */
3656 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3664 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3666 int ret = MM_ERROR_NONE;
3670 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3671 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3673 LOGD("current state before doing transition");
3674 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3675 MMPLAYER_PRINT_STATE(player);
3677 /* set pipeline status to PAUSED */
3678 ret = _mmplayer_gst_set_state(player,
3679 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3684 if (ret != MM_ERROR_NONE) {
3685 GstMessage *msg = NULL;
3686 GTimer *timer = NULL;
3687 gdouble MAX_TIMEOUT_SEC = 3;
3689 LOGE("failed to set state to PAUSED");
3691 if (!player->bus_watcher) {
3692 LOGE("there is no bus msg thread. pipeline is shutting down.");
3696 if (player->msg_posted) {
3697 LOGE("error msg is already posted.");
3701 timer = g_timer_new();
3702 g_timer_start(timer);
3704 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3707 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3709 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3710 GError *error = NULL;
3712 /* parse error code */
3713 gst_message_parse_error(msg, &error, NULL);
3715 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3716 /* Note : the streaming error from the streaming source is handled
3717 * using __mmplayer_handle_streaming_error.
3719 __mmplayer_handle_streaming_error(player, msg, error);
3722 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3724 if (error->domain == GST_STREAM_ERROR)
3725 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3726 else if (error->domain == GST_RESOURCE_ERROR)
3727 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3728 else if (error->domain == GST_LIBRARY_ERROR)
3729 ret = __mmplayer_gst_handle_library_error(player, error->code);
3730 else if (error->domain == GST_CORE_ERROR)
3731 ret = __mmplayer_gst_handle_core_error(player, error->code);
3733 g_error_free(error);
3735 player->msg_posted = TRUE;
3737 gst_message_unref(msg);
3739 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3741 gst_object_unref(bus);
3742 g_timer_stop(timer);
3743 g_timer_destroy(timer);
3748 if (MMPLAYER_USE_DECODEBIN(player)) {
3749 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3750 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3751 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3754 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3757 /* generate dot file before returning error */
3758 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3766 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3768 int ret = MM_ERROR_NONE;
3773 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3774 MM_ERROR_PLAYER_NOT_INITIALIZED);
3776 LOGD("current state before doing transition");
3777 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3778 MMPLAYER_PRINT_STATE(player);
3781 LOGD("do async state transition to PLAYING");
3783 /* set pipeline state to PLAYING */
3784 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3786 ret = _mmplayer_gst_set_state(player,
3787 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3788 if (ret != MM_ERROR_NONE) {
3789 LOGE("failed to set state to PLAYING");
3794 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3797 /* generate dot file */
3798 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3805 /* sending event to one of sinkelements */
3807 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3809 GstEvent *event2 = NULL;
3810 GList *sinks = NULL;
3811 gboolean res = FALSE;
3814 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3815 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3817 /* While adding subtitles in live feeds seek is getting called.
3818 Adding defensive check in framework layer.*/
3819 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3820 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3821 LOGE("Should not send seek event during live playback");
3826 if (player->play_subtitle)
3827 event2 = gst_event_copy((const GstEvent *)event);
3829 sinks = player->sink_elements;
3831 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3833 if (GST_IS_ELEMENT(sink)) {
3834 /* keep ref to the event */
3835 gst_event_ref(event);
3837 if ((res = gst_element_send_event(sink, event))) {
3838 LOGD("sending event[%s] to sink element [%s] success!",
3839 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3841 /* rtsp case, async_done is not called after seek during pause state */
3842 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3843 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3844 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3845 LOGD("RTSP seek completed, after pause state..");
3846 player->seek_state = MMPLAYER_SEEK_NONE;
3847 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3853 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3854 sinks = g_list_next(sinks);
3861 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3862 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3865 sinks = g_list_next(sinks);
3868 /* Note : Textbin is not linked to the video or audio bin.
3869 * It needs to send the event to the text sink separately.
3871 if (player->play_subtitle && player->pipeline) {
3872 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3874 if (GST_IS_ELEMENT(text_sink)) {
3875 /* keep ref to the event */
3876 gst_event_ref(event2);
3878 if ((res = gst_element_send_event(text_sink, event2)))
3879 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3880 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3882 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3883 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3885 gst_event_unref(event2);
3889 gst_event_unref(event);
3897 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3898 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3899 gint64 cur, GstSeekType stop_type, gint64 stop)
3901 GstEvent *event = NULL;
3902 gboolean result = FALSE;
3906 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3908 if (player->pipeline && player->pipeline->textbin)
3909 __mmplayer_drop_subtitle(player, FALSE);
3911 event = gst_event_new_seek(rate, format, flags, cur_type,
3912 cur, stop_type, stop);
3914 result = _mmplayer_gst_send_event_to_sink(player, event);
3922 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3924 int ret = MM_ERROR_NONE;
3925 gint64 pos_nsec = 0;
3926 gboolean accurate = FALSE;
3927 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3930 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3931 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3933 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3934 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3937 ret = __mmplayer_gst_check_position(player, position);
3938 if (ret != MM_ERROR_NONE) {
3939 LOGW("result of check position info 0x%X", ret);
3940 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3943 if (!__mmplayer_gst_check_seekable(player))
3944 return MM_ERROR_PLAYER_NO_OP;
3946 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3947 position, player->playback_rate, player->duration);
3949 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3950 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3951 This causes problem is position calculation during normal pause resume scenarios also.
3952 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3953 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3954 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3955 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3956 LOGW("getting current position failed in seek");
3958 player->last_position = pos_nsec;
3959 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3962 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3963 LOGD("not completed seek");
3964 return MM_ERROR_PLAYER_DOING_SEEK;
3967 if (!internal_called)
3968 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3970 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3971 that's why set position through property. */
3972 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3973 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3974 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3975 (!player->videodec_linked) && (!player->audiodec_linked)) {
3977 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3978 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3980 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3981 player->seek_state = MMPLAYER_SEEK_NONE;
3982 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3984 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3986 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3988 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3990 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3991 GST_FORMAT_TIME, seek_flags,
3992 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3993 LOGE("failed to set position");
3998 /* NOTE : store last seeking point to overcome some bad operation
3999 * (returning zero when getting current position) of some elements
4001 player->last_position = position;
4003 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4004 if (player->playback_rate > 1.0)
4005 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4007 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4008 LOGD("buffering should be reset after seeking");
4009 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4010 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4014 return MM_ERROR_NONE;
4017 player->pending_seek.is_pending = true;
4018 player->pending_seek.pos = position;
4020 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4021 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4022 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4023 player->pending_seek.pos);
4025 return MM_ERROR_NONE;
4028 player->seek_state = MMPLAYER_SEEK_NONE;
4029 return MM_ERROR_PLAYER_SEEK;
4033 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4035 #define TRICKPLAY_OFFSET GST_MSECOND
4037 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4038 gint64 pos_nsec = 0;
4039 gboolean ret = TRUE;
4041 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4042 MM_ERROR_PLAYER_NOT_INITIALIZED);
4044 current_state = MMPLAYER_CURRENT_STATE(player);
4046 /* NOTE : query position except paused state to overcome some bad operation
4047 * please refer to below comments in details
4049 if (current_state != MM_PLAYER_STATE_PAUSED)
4050 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4052 /* NOTE : get last point to overcome some bad operation of some elements
4053 *(returning zero when getting current position in paused state
4054 * and when failed to get position during seeking
4056 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4057 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4059 if (player->playback_rate < 0.0)
4060 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4062 pos_nsec = player->last_position;
4065 pos_nsec = player->last_position;
4067 player->last_position = pos_nsec;
4069 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4072 if (player->duration > 0 && pos_nsec > player->duration)
4073 pos_nsec = player->duration;
4075 player->last_position = pos_nsec;
4078 *position = pos_nsec;
4080 return MM_ERROR_NONE;
4084 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4086 #define STREAMING_IS_FINISHED 0
4087 #define BUFFERING_MAX_PER 100
4088 #define DEFAULT_PER_VALUE -1
4089 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4091 mmplayer_gst_element_t *mainbin = NULL;
4092 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4093 gint64 buffered_total = 0;
4094 gint64 position = 0;
4095 gint buffered_sec = -1;
4096 GstBufferingMode mode = GST_BUFFERING_STREAM;
4097 gint64 content_size_time = player->duration;
4098 guint64 content_size_bytes = player->http_content_size;
4100 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4102 player->pipeline->mainbin,
4103 MM_ERROR_PLAYER_NOT_INITIALIZED);
4105 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4110 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4111 /* and rtsp is not ready yet. */
4112 LOGW("it's only used for http streaming case");
4113 return MM_ERROR_PLAYER_NO_OP;
4116 if (content_size_time <= 0 || content_size_bytes <= 0) {
4117 LOGW("there is no content size");
4118 return MM_ERROR_NONE;
4121 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4122 LOGW("fail to get current position");
4123 return MM_ERROR_NONE;
4126 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4127 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4129 mainbin = player->pipeline->mainbin;
4130 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4132 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4133 GstQuery *query = NULL;
4134 gint byte_in_rate = 0, byte_out_rate = 0;
4135 gint64 estimated_total = 0;
4137 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4138 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4139 LOGW("fail to get buffering query from queue2");
4141 gst_query_unref(query);
4142 return MM_ERROR_NONE;
4145 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4146 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4148 if (mode == GST_BUFFERING_STREAM) {
4149 /* using only queue in case of push mode(ts / mp3) */
4150 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4151 GST_FORMAT_BYTES, &buffered_total)) {
4152 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4153 end_per = 100 * buffered_total / content_size_bytes;
4156 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4158 guint num_of_ranges = 0;
4159 gint64 start_byte = 0, stop_byte = 0;
4161 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4162 if (estimated_total != STREAMING_IS_FINISHED) {
4163 /* buffered size info from queue2 */
4164 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4165 for (idx = 0; idx < num_of_ranges; idx++) {
4166 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4167 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4169 buffered_total += (stop_byte - start_byte);
4172 end_per = BUFFERING_MAX_PER;
4175 gst_query_unref(query);
4178 if (end_per == DEFAULT_PER_VALUE) {
4179 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4181 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4183 /* buffered size info from multiqueue */
4184 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4185 guint curr_size_bytes = 0;
4186 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4187 "curr-size-bytes", &curr_size_bytes, NULL);
4188 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4189 buffered_total += curr_size_bytes;
4192 if (avg_byterate > 0)
4193 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4194 else if (player->total_maximum_bitrate > 0)
4195 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4196 else if (player->total_bitrate > 0)
4197 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4199 if (buffered_sec >= 0)
4200 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4204 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4205 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4207 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4208 buffered_total, buffered_sec, *start_pos, *end_pos);
4210 return MM_ERROR_NONE;
4214 _mmplayer_gst_create_source(mmplayer_t *player)
4216 GstElement *element = NULL;
4219 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4220 player->pipeline->mainbin, NULL);
4222 /* setup source for gapless play */
4223 switch (player->profile.uri_type) {
4225 case MM_PLAYER_URI_TYPE_FILE:
4226 element = __mmplayer_gst_make_file_src(player);
4228 case MM_PLAYER_URI_TYPE_URL_HTTP:
4229 element = __mmplayer_gst_make_http_src(player);
4232 LOGE("not support uri type %d", player->profile.uri_type);
4237 LOGE("failed to create source element");
4246 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4250 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4252 SECURE_LOGD("uri : %s", player->profile.uri);
4254 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4256 if ((player->v_stream_caps) &&
4257 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4258 return MM_ERROR_PLAYER_INTERNAL;
4260 if ((player->a_stream_caps) &&
4261 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4262 return MM_ERROR_PLAYER_INTERNAL;
4264 if ((player->s_stream_caps) &&
4265 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4266 return MM_ERROR_PLAYER_INTERNAL;
4269 return MM_ERROR_NONE;
4273 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4275 mmplayer_gst_element_t *mainbin = NULL;
4276 GstElement *autoplug_elem = NULL;
4279 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4280 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4282 mainbin = player->pipeline->mainbin;
4284 LOGD("uri type %d", player->profile.uri_type);
4286 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4287 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4288 return MM_ERROR_PLAYER_INTERNAL;
4291 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4292 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4295 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4296 if (!autoplug_elem) {
4297 LOGE("failed to create uridecodebin3 element");
4301 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4302 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4303 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4305 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4306 LOGE("failed to add uridecodebin to pipeline");
4310 /* FIXME: required ?*/
4311 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4312 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4313 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4315 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4316 LOGE("failed to create fakesink");
4319 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4321 /* take ownership of fakesink. we are reusing it */
4322 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4324 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4325 LOGE("failed to add fakesink to bin");
4326 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4331 return MM_ERROR_NONE;
4335 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4336 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4338 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4339 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4341 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4342 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4344 return MM_ERROR_PLAYER_INTERNAL;
4348 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4350 mmplayer_gst_element_t *mainbin = NULL;
4351 GstElement *src_elem = NULL;
4352 GstElement *autoplug_elem = NULL;
4353 GList *element_bucket = NULL;
4354 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4357 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4358 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4360 LOGD("uri type %d", player->profile.uri_type);
4362 /* create source element */
4363 switch (player->profile.uri_type) {
4364 case MM_PLAYER_URI_TYPE_URL_RTSP:
4365 src_elem = __mmplayer_gst_make_rtsp_src(player);
4367 case MM_PLAYER_URI_TYPE_URL_HTTP:
4368 src_elem = __mmplayer_gst_make_http_src(player);
4370 case MM_PLAYER_URI_TYPE_FILE:
4371 src_elem = __mmplayer_gst_make_file_src(player);
4373 case MM_PLAYER_URI_TYPE_SS:
4375 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4376 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4378 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4382 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4383 LOGD("get timeout from ini");
4384 http_timeout = player->ini.http_timeout;
4387 /* setting property to streaming source */
4388 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4391 case MM_PLAYER_URI_TYPE_MEM:
4393 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4395 src_elem = gst_element_factory_make("appsrc", "mem-source");
4397 LOGE("failed to create appsrc element");
4401 g_object_set(src_elem, "stream-type", stream_type,
4402 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4404 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4405 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4406 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4407 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4411 LOGE("not support uri type");
4416 LOGE("failed to create source element");
4417 return MM_ERROR_PLAYER_INTERNAL;
4420 mainbin = player->pipeline->mainbin;
4422 /* take source element */
4423 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4425 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4426 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4427 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4429 /* create next element for auto-plugging */
4430 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4431 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4432 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4433 if (!autoplug_elem) {
4434 LOGE("failed to create typefind element");
4438 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4439 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4440 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4441 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4442 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4443 if (!autoplug_elem) {
4444 LOGE("failed to create decodebin");
4448 /* default size of mq in decodebin is 2M
4449 * but it can cause blocking issue during seeking depends on content. */
4450 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4453 if (autoplug_elem) {
4454 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4455 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4456 mainbin[autoplug_elem_id].gst = autoplug_elem;
4458 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4461 /* add elements to pipeline */
4462 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4463 LOGE("failed to add elements to pipeline");
4467 /* linking elements in the bucket by added order. */
4468 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4469 LOGE("failed to link some elements");
4473 /* FIXME: need to check whether this is required or not. */
4474 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4475 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4476 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4477 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4478 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4480 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4481 LOGE("failed to create fakesink");
4484 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4486 /* take ownership of fakesink. we are reusing it */
4487 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4489 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4490 LOGE("failed to add fakesink to bin");
4491 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4496 g_list_free(element_bucket);
4499 return MM_ERROR_NONE;
4502 g_list_free(element_bucket);
4504 if (mainbin[MMPLAYER_M_SRC].gst)
4505 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4507 if (mainbin[autoplug_elem_id].gst)
4508 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4510 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4511 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4513 mainbin[MMPLAYER_M_SRC].gst = NULL;
4514 mainbin[autoplug_elem_id].gst = NULL;
4515 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4517 return MM_ERROR_PLAYER_INTERNAL;
4521 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4524 mmplayer_gst_element_t *mainbin = NULL;
4527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4528 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4530 mainbin = player->pipeline->mainbin;
4532 /* connect bus callback */
4533 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4535 LOGE("cannot get bus from pipeline");
4536 return MM_ERROR_PLAYER_INTERNAL;
4539 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4540 (GstBusFunc)__mmplayer_gst_msg_push, player,
4541 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4542 if (player->bus_watcher == 0) {
4543 LOGE("failed to add bus watch");
4544 return MM_ERROR_PLAYER_INTERNAL;
4547 g_mutex_init(&player->bus_watcher_mutex);
4548 g_cond_init(&player->bus_watcher_cond);
4550 player->context.thread_default = g_main_context_get_thread_default();
4551 if (player->context.thread_default == NULL) {
4552 player->context.thread_default = g_main_context_default();
4553 LOGD("thread-default context is the global default context");
4555 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4557 /* set sync handler to get tag synchronously */
4558 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4559 gst_object_unref(GST_OBJECT(bus));
4561 /* create gst bus_msb_cb thread */
4562 g_mutex_init(&player->bus_msg_thread_mutex);
4563 g_cond_init(&player->bus_msg_thread_cond);
4564 player->bus_msg_thread_exit = FALSE;
4565 player->bus_msg_thread =
4566 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4567 if (!player->bus_msg_thread) {
4568 LOGE("failed to create gst BUS msg thread");
4569 g_mutex_clear(&player->bus_msg_thread_mutex);
4570 g_cond_clear(&player->bus_msg_thread_cond);
4571 return MM_ERROR_PLAYER_INTERNAL;
4575 return MM_ERROR_NONE;
4579 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4581 int ret = MM_ERROR_NONE;
4582 mmplayer_gst_element_t *mainbin = NULL;
4583 MMMessageParamType msg_param = {0,};
4584 GstElement *element = NULL;
4585 MMHandleType attrs = 0;
4587 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4591 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4592 LOGE("player is not initialized");
4596 mainbin = player->pipeline->mainbin;
4597 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4599 attrs = MMPLAYER_GET_ATTRS(player);
4601 LOGE("fail to get attributes");
4605 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4607 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4608 LOGE("failed to parse profile");
4609 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4613 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4614 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4615 LOGE("dash or hls is not supportable");
4616 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4620 if (!MMPLAYER_USE_DECODEBIN(player)) {
4621 ret = _mmplayer_gst_build_pipeline_with_src(player);
4622 if (ret != MM_ERROR_NONE)
4625 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4626 LOGE("Failed to change state of uridecodebin3 element");
4632 element = _mmplayer_gst_create_source(player);
4634 LOGE("no source element was created");
4638 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4639 LOGE("failed to add source element to pipeline");
4640 gst_object_unref(GST_OBJECT(element));
4645 /* take source element */
4646 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4647 mainbin[MMPLAYER_M_SRC].gst = element;
4651 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4652 if (player->streamer == NULL) {
4653 player->streamer = _mm_player_streaming_create();
4654 _mm_player_streaming_initialize(player->streamer, TRUE);
4657 elem_idx = MMPLAYER_M_TYPEFIND;
4658 element = gst_element_factory_make("typefind", "typefinder");
4659 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4660 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4662 elem_idx = MMPLAYER_M_AUTOPLUG;
4663 element = _mmplayer_gst_make_decodebin(player);
4666 /* check autoplug element is OK */
4668 LOGE("can not create element(%d)", elem_idx);
4672 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4673 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4674 gst_object_unref(GST_OBJECT(element));
4679 mainbin[elem_idx].id = elem_idx;
4680 mainbin[elem_idx].gst = element;
4682 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4683 LOGE("Failed to link src - autoplug(or typefind)");
4687 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4688 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4689 LOGE("Failed to change state of src element");
4693 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4694 LOGE("Failed to change state of decodebin");
4699 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4700 LOGE("Failed to change state of src element");
4705 player->gapless.stream_changed = TRUE;
4706 player->gapless.running = TRUE;
4712 _mmplayer_set_reconfigure_state(player, FALSE);
4713 if (!player->msg_posted) {
4714 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4715 player->msg_posted = TRUE;