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;
983 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
984 if (!player->streamer->is_adaptive_streaming) {
985 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
989 /* adaptivedemux2 is used for buffering in uridecodebin3 */
990 if (!player->streamer->buffering_req.is_pre_buffering) {
991 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
992 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
993 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
999 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1001 int ret = MM_ERROR_NONE;
1002 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1003 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1004 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1005 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1007 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1008 LOGW("do nothing for buffering msg");
1009 ret = MM_ERROR_PLAYER_INVALID_STATE;
1013 prev_state = MMPLAYER_PREV_STATE(player);
1014 current_state = MMPLAYER_CURRENT_STATE(player);
1015 target_state = MMPLAYER_TARGET_STATE(player);
1016 pending_state = MMPLAYER_PENDING_STATE(player);
1018 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1019 MMPLAYER_STATE_GET_NAME(prev_state),
1020 MMPLAYER_STATE_GET_NAME(current_state),
1021 MMPLAYER_STATE_GET_NAME(pending_state),
1022 MMPLAYER_STATE_GET_NAME(target_state),
1023 player->streamer->buffering_state);
1025 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1026 /* NOTE : if buffering has done, player has to go to target state. */
1027 switch (target_state) {
1028 case MM_PLAYER_STATE_PAUSED:
1030 switch (pending_state) {
1031 case MM_PLAYER_STATE_PLAYING:
1032 _mmplayer_gst_pause(player, TRUE);
1035 case MM_PLAYER_STATE_PAUSED:
1036 LOGD("player is already going to paused state, there is nothing to do.");
1039 case MM_PLAYER_STATE_NONE:
1040 case MM_PLAYER_STATE_NULL:
1041 case MM_PLAYER_STATE_READY:
1043 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1049 case MM_PLAYER_STATE_PLAYING:
1051 switch (pending_state) {
1052 case MM_PLAYER_STATE_NONE:
1054 if (current_state != MM_PLAYER_STATE_PLAYING)
1055 _mmplayer_gst_resume(player, TRUE);
1059 case MM_PLAYER_STATE_PAUSED:
1060 /* NOTE: It should be worked as asynchronously.
1061 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1063 if (current_state == MM_PLAYER_STATE_PLAYING) {
1064 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1065 * The current state should be changed to paused purposely to prevent state conflict.
1067 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1069 _mmplayer_gst_resume(player, TRUE);
1072 case MM_PLAYER_STATE_PLAYING:
1073 LOGD("player is already going to playing state, there is nothing to do.");
1076 case MM_PLAYER_STATE_NULL:
1077 case MM_PLAYER_STATE_READY:
1079 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1085 case MM_PLAYER_STATE_NULL:
1086 case MM_PLAYER_STATE_READY:
1087 case MM_PLAYER_STATE_NONE:
1089 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1093 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1094 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1096 switch (pending_state) {
1097 case MM_PLAYER_STATE_NONE:
1099 if (current_state != MM_PLAYER_STATE_PAUSED) {
1100 /* rtsp streaming pause makes rtsp server stop sending data. */
1101 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1102 LOGD("set pause state during buffering");
1103 _mmplayer_gst_pause(player, TRUE);
1109 case MM_PLAYER_STATE_PLAYING:
1110 /* rtsp streaming pause makes rtsp server stop sending data. */
1111 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1112 _mmplayer_gst_pause(player, TRUE);
1115 case MM_PLAYER_STATE_PAUSED:
1118 case MM_PLAYER_STATE_NULL:
1119 case MM_PLAYER_STATE_READY:
1121 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1130 static stream_variant_t *
1131 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1133 stream_variant_t *var_info = NULL;
1134 g_return_val_if_fail(self != NULL, NULL);
1136 var_info = g_new0(stream_variant_t, 1);
1137 if (!var_info) return NULL;
1138 var_info->bandwidth = self->bandwidth;
1139 var_info->width = self->width;
1140 var_info->height = self->height;
1145 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1151 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1152 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1154 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1155 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1156 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1158 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1159 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1160 player->http_content_size = (bytes > 0) ? bytes : 0;
1163 /* handling audio clip which has vbr. means duration is keep changing */
1164 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1173 __mmplayer_eos_timer_cb(gpointer u_data)
1175 mmplayer_t *player = NULL;
1176 MMHandleType attrs = 0;
1179 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1181 player = (mmplayer_t *)u_data;
1182 attrs = MMPLAYER_GET_ATTRS(player);
1184 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1188 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1189 if (ret_value != MM_ERROR_NONE)
1190 LOGE("seeking to 0 failed in repeat play");
1193 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1196 /* we are returning FALSE as we need only one posting */
1201 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1203 MMPLAYER_RETURN_IF_FAIL(player);
1205 /* post now if delay is zero */
1206 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1207 LOGD("eos delay is zero. posting EOS now");
1208 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1210 if (player->audio_decoded_cb)
1211 _mmplayer_cancel_eos_timer(player);
1216 /* cancel if existing */
1217 _mmplayer_cancel_eos_timer(player);
1219 /* init new timeout */
1220 /* NOTE : consider give high priority to this timer */
1221 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1223 player->eos_timer = g_timeout_add(delay_in_ms,
1224 __mmplayer_eos_timer_cb, player);
1226 player->context.global_default = g_main_context_default();
1227 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1229 /* check timer is valid. if not, send EOS now */
1230 if (player->eos_timer == 0) {
1231 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1232 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1237 __mmplayer_gst_pending_seek(mmplayer_t *player)
1239 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1240 int ret = MM_ERROR_NONE;
1244 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1246 if (!player->pending_seek.is_pending) {
1247 LOGD("pending seek is not reserved. nothing to do.");
1251 /* check player state if player could pending seek or not. */
1252 current_state = MMPLAYER_CURRENT_STATE(player);
1254 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1255 LOGW("try to pending seek in %s state, try next time. ",
1256 MMPLAYER_STATE_GET_NAME(current_state));
1260 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1262 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1263 if (ret != MM_ERROR_NONE)
1264 LOGE("failed to seek pending position. just keep staying current position.");
1266 player->pending_seek.is_pending = false;
1274 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1276 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1278 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1280 audiobin = player->pipeline->audiobin; /* can be null */
1281 videobin = player->pipeline->videobin; /* can be null */
1282 textbin = player->pipeline->textbin; /* can be null */
1284 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1286 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1287 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1289 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1290 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1292 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1293 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1299 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1301 mmplayer_gst_element_t *textbin;
1304 MMPLAYER_RETURN_IF_FAIL(player &&
1306 player->pipeline->textbin);
1308 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1310 textbin = player->pipeline->textbin;
1313 LOGD("Drop subtitle text after getting EOS");
1315 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1316 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1318 player->is_subtitle_force_drop = TRUE;
1320 if (player->is_subtitle_force_drop == TRUE) {
1321 LOGD("Enable subtitle data path without drop");
1323 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1324 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1326 LOGD("non-connected with external display");
1328 player->is_subtitle_force_drop = FALSE;
1334 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1336 MMHandleType attrs = 0;
1341 /* NOTE : EOS event is coming multiple time. watch out it */
1342 /* check state. we only process EOS when pipeline state goes to PLAYING */
1343 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1344 LOGD("EOS received on non-playing state. ignoring it");
1348 if (player->pipeline && player->pipeline->textbin)
1349 __mmplayer_drop_subtitle(player, TRUE);
1351 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1352 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1354 /* rewind if repeat count is greater then zero */
1355 /* get play count */
1356 attrs = MMPLAYER_GET_ATTRS(player);
1358 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1360 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1362 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1363 if (player->playback_rate < 0.0) {
1364 player->resumed_by_rewind = TRUE;
1365 _mmplayer_set_mute((MMHandleType)player, false);
1366 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1369 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1372 player->sent_bos = FALSE;
1374 LOGD("do not post eos msg for repeating");
1379 if (player->pipeline)
1380 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1382 /* post eos message to application */
1383 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1385 /* reset last position */
1386 player->last_position = 0;
1393 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1395 GError *error = NULL;
1396 gchar *debug = NULL;
1400 /* generating debug info before returning error */
1401 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1403 /* get error code */
1404 gst_message_parse_error(msg, &error, &debug);
1406 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1407 /* Note : the streaming error from the streaming source is handled
1408 * using __mmplayer_handle_streaming_error.
1410 __mmplayer_handle_streaming_error(player, msg, error);
1412 /* dump state of all element */
1413 _mmplayer_dump_pipeline_state(player);
1415 /* translate gst error code to msl error code. then post it
1416 * to application if needed
1418 __mmplayer_handle_gst_error(player, msg, error);
1421 LOGE("error debug : %s", debug);
1424 MMPLAYER_FREEIF(debug);
1425 g_error_free(error);
1432 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1434 MMMessageParamType msg_param = {0, };
1435 int bRet = MM_ERROR_NONE;
1438 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1440 if (!MMPLAYER_IS_STREAMING(player)) {
1441 LOGW("this is not streaming playback.");
1445 MMPLAYER_CMD_LOCK(player);
1447 if (!player->streamer) {
1448 LOGW("Pipeline is shutting down");
1449 MMPLAYER_CMD_UNLOCK(player);
1453 /* ignore the remained buffering message till getting 100% msg */
1454 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1455 gint buffer_percent = 0;
1457 gst_message_parse_buffering(msg, &buffer_percent);
1459 if (buffer_percent == MAX_BUFFER_PERCENT) {
1460 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1461 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1462 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1464 MMPLAYER_CMD_UNLOCK(player);
1468 /* ignore the remained buffering message */
1469 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1470 gint buffer_percent = 0;
1472 gst_message_parse_buffering(msg, &buffer_percent);
1474 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1475 player->streamer->buffering_percent, buffer_percent);
1477 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1478 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1479 player->streamer->buffering_req.is_pre_buffering = FALSE;
1481 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1483 LOGD("interrupted buffering - ignored the remained buffering msg!");
1484 MMPLAYER_CMD_UNLOCK(player);
1489 __mmplayer_update_buffer_setting(player, msg);
1491 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1493 if (bRet == MM_ERROR_NONE) {
1494 msg_param.connection.buffering = player->streamer->buffering_percent;
1495 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1497 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1498 player->pending_resume &&
1499 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1501 player->is_external_subtitle_added_now = FALSE;
1502 player->pending_resume = FALSE;
1503 _mmplayer_resume((MMHandleType)player);
1506 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1507 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1510 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1511 player->seek_state = MMPLAYER_SEEK_NONE;
1512 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1513 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1514 /* Considering the async state transition in case of RTSP.
1515 After getting state change gst msg, seek completed msg will be posted. */
1516 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1520 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1521 if (!player->streamer) {
1522 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1523 MMPLAYER_CMD_UNLOCK(player);
1527 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1529 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1530 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1532 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1533 msg_param.connection.buffering = player->streamer->buffering_percent;
1534 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1536 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1539 msg_param.connection.buffering = player->streamer->buffering_percent;
1540 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1543 MMPLAYER_CMD_UNLOCK(player);
1551 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1553 mmplayer_gst_element_t *mainbin;
1554 const GValue *voldstate, *vnewstate, *vpending;
1555 GstState oldstate = GST_STATE_NULL;
1556 GstState newstate = GST_STATE_NULL;
1557 GstState pending = GST_STATE_NULL;
1560 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1562 mainbin = player->pipeline->mainbin;
1564 /* we only handle messages from pipeline */
1565 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1568 /* get state info from msg */
1569 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1570 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1571 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1573 if (!voldstate || !vnewstate) {
1574 LOGE("received msg has wrong format.");
1578 oldstate = (GstState)voldstate->data[0].v_int;
1579 newstate = (GstState)vnewstate->data[0].v_int;
1581 pending = (GstState)vpending->data[0].v_int;
1583 LOGD("state changed [%s] : %s ---> %s final : %s",
1584 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1585 gst_element_state_get_name((GstState)oldstate),
1586 gst_element_state_get_name((GstState)newstate),
1587 gst_element_state_get_name((GstState)pending));
1589 if (newstate == GST_STATE_PLAYING) {
1590 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1592 int retVal = MM_ERROR_NONE;
1593 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1595 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1597 if (MM_ERROR_NONE != retVal)
1598 LOGE("failed to seek pending position. just keep staying current position.");
1600 player->pending_seek.is_pending = false;
1604 if (oldstate == newstate) {
1605 LOGD("pipeline reports state transition to old state");
1610 case GST_STATE_PAUSED:
1612 gboolean prepare_async = FALSE;
1614 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1615 // managed prepare async case
1616 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1617 LOGD("checking prepare mode for async transition - %d", prepare_async);
1620 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1621 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1623 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1624 _mm_player_streaming_set_content_bitrate(player->streamer,
1625 player->total_maximum_bitrate, player->total_bitrate);
1627 if (player->pending_seek.is_pending) {
1628 LOGW("trying to do pending seek");
1629 MMPLAYER_CMD_LOCK(player);
1630 __mmplayer_gst_pending_seek(player);
1631 MMPLAYER_CMD_UNLOCK(player);
1637 case GST_STATE_PLAYING:
1639 if (MMPLAYER_IS_STREAMING(player)) {
1640 // managed prepare async case when buffering is completed
1641 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1642 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1643 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1644 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1646 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1648 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1649 if (player->streamer->buffering_percent < 100) {
1651 MMMessageParamType msg_param = {0, };
1652 LOGW("Posting Buffering Completed Message to Application !!!");
1654 msg_param.connection.buffering = 100;
1655 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1660 if (player->gapless.stream_changed) {
1661 _mmplayer_update_content_attrs(player, ATTR_ALL);
1662 player->gapless.stream_changed = FALSE;
1665 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1666 player->seek_state = MMPLAYER_SEEK_NONE;
1667 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1671 case GST_STATE_VOID_PENDING:
1672 case GST_STATE_NULL:
1673 case GST_STATE_READY:
1683 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1685 const gchar *structure_name;
1686 gint count = 0, idx = 0;
1689 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1691 if (gst_message_get_structure(msg) == NULL)
1694 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1695 if (!structure_name)
1698 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1700 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1701 const GValue *var_info = NULL;
1703 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1704 if (var_info != NULL) {
1705 if (player->adaptive_info.var_list)
1706 g_list_free_full(player->adaptive_info.var_list, g_free);
1708 /* share addr or copy the list */
1709 player->adaptive_info.var_list =
1710 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1712 count = g_list_length(player->adaptive_info.var_list);
1714 stream_variant_t *temp = NULL;
1716 /* print out for debug */
1717 LOGD("num of variant_info %d", count);
1718 for (idx = 0; idx < count; idx++) {
1719 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1721 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1727 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1728 gint num_buffers = 0;
1729 gint extra_num_buffers = 0;
1731 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1732 LOGD("video_num_buffers : %d", num_buffers);
1733 mm_player_set_attribute((MMHandleType)player, NULL,
1734 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1737 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1738 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1739 mm_player_set_attribute((MMHandleType)player, NULL,
1740 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1745 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1746 _mmplayer_track_update_text_attr_info(player, msg);
1748 /* custom message */
1749 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1750 MMMessageParamType msg_param = {0,};
1751 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1752 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1755 /* custom message for RTSP attribute :
1756 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1757 sdp which has contents info is received when rtsp connection is opened.
1758 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1759 if (!strcmp(structure_name, "rtspsrc_properties")) {
1760 g_autofree gchar *audio_codec = NULL;
1761 g_autofree gchar *video_codec = NULL;
1762 g_autofree gchar *video_frame_size = NULL;
1764 gst_structure_get(gst_message_get_structure(msg),
1765 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1766 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1767 player->streaming_type = _mmplayer_get_stream_service_type(player);
1769 gst_structure_get(gst_message_get_structure(msg),
1770 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1771 LOGD("rtsp_audio_codec : %s", audio_codec);
1773 mm_player_set_attribute((MMHandleType)player, NULL,
1774 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1776 gst_structure_get(gst_message_get_structure(msg),
1777 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1778 LOGD("rtsp_video_codec : %s", video_codec);
1780 mm_player_set_attribute((MMHandleType)player, NULL,
1781 "content_video_codec", video_codec, strlen(video_codec), NULL);
1783 gst_structure_get(gst_message_get_structure(msg),
1784 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1785 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1786 if (video_frame_size) {
1787 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1788 mm_player_set_attribute((MMHandleType)player, NULL,
1789 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1790 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1792 g_strfreev(res_str);
1801 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1803 mmplayer_gst_element_t *mainbin;
1806 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1808 mainbin = player->pipeline->mainbin;
1810 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1812 /* we only handle messages from pipeline */
1813 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1816 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1817 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1818 player->seek_state = MMPLAYER_SEEK_NONE;
1819 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1820 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1821 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1822 LOGD("sync %s state(%s) with parent state(%s)",
1823 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1824 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1825 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1827 /* In case of streaming, pause is required before finishing seeking by buffering.
1828 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1829 Because the buffering state is controlled according to the state transition for force resume,
1830 the decodebin state should be paused as player state. */
1831 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1834 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1835 (player->streamer) &&
1836 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1837 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1838 GstQuery *query = NULL;
1839 gboolean busy = FALSE;
1842 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1843 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1844 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1845 gst_query_parse_buffering_percent(query, &busy, &percent);
1846 gst_query_unref(query);
1848 LOGD("buffered percent(%s): %d",
1849 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1853 __mmplayer_handle_buffering_playback(player);
1856 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1866 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1868 GValue val = { 0, };
1870 guint indent = GPOINTER_TO_UINT(user_data);
1872 if (!gst_tag_list_copy_value(&val, tags, tag))
1875 if (G_VALUE_HOLDS_STRING(&val))
1876 str = g_value_dup_string(&val);
1878 str = gst_value_serialize(&val);
1880 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1882 g_value_unset(&val);
1887 __mmplayer_dump_collection(GstStreamCollection * collection)
1891 GstTagList *tags = NULL;
1893 GstCaps *caps = NULL;
1895 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1896 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1897 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1898 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1899 gst_stream_get_stream_flags(stream));
1900 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1902 caps = gst_stream_get_caps(stream);
1904 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1905 gst_caps_unref(caps);
1909 tags = gst_stream_get_tags(stream);
1912 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1913 gst_tag_list_unref(tags);
1920 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1921 GstStream *stream, GParamSpec *pspec, gpointer data)
1923 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1924 gst_stream_get_stream_id(stream), pspec->name, collection);
1925 if (g_str_equal(pspec->name, "caps")) {
1926 GstCaps *caps = gst_stream_get_caps(stream);
1927 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1928 gst_caps_unref(caps);
1932 if (g_str_equal (pspec->name, "tags")) {
1933 GstTagList *tags = gst_stream_get_tags(stream);
1936 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1937 gst_tag_list_unref(tags);
1944 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1946 mmplayer_t *player = (mmplayer_t *)(data);
1948 MMPLAYER_RETURN_IF_FAIL(player);
1949 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1951 switch (GST_MESSAGE_TYPE(msg)) {
1952 case GST_MESSAGE_UNKNOWN:
1953 LOGD("unknown message received");
1956 case GST_MESSAGE_EOS:
1957 LOGD("GST_MESSAGE_EOS received");
1958 __mmplayer_gst_handle_eos_message(player, msg);
1961 case GST_MESSAGE_ERROR:
1962 _mmplayer_set_reconfigure_state(player, FALSE);
1963 __mmplayer_gst_handle_error_message(player, msg);
1966 case GST_MESSAGE_WARNING:
1969 GError *error = NULL;
1971 gst_message_parse_warning(msg, &error, &debug);
1973 LOGD("warning : %s", error->message);
1974 LOGD("debug : %s", debug);
1976 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1978 MMPLAYER_FREEIF(debug);
1979 g_error_free(error);
1983 case GST_MESSAGE_TAG:
1985 LOGD("GST_MESSAGE_TAG");
1986 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1987 LOGW("failed to extract tags from gstmessage");
1991 case GST_MESSAGE_BUFFERING:
1992 __mmplayer_gst_handle_buffering_message(player, msg);
1995 case GST_MESSAGE_STATE_CHANGED:
1996 __mmplayer_gst_handle_state_message(player, msg);
1999 case GST_MESSAGE_CLOCK_LOST:
2001 GstClock *clock = NULL;
2002 gboolean need_new_clock = FALSE;
2004 gst_message_parse_clock_lost(msg, &clock);
2005 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2007 if (!player->videodec_linked)
2008 need_new_clock = TRUE;
2009 else if (!player->ini.use_system_clock)
2010 need_new_clock = TRUE;
2012 if (need_new_clock) {
2013 LOGD("Provide clock is TRUE, do pause->resume");
2014 _mmplayer_gst_pause(player, FALSE);
2015 _mmplayer_gst_resume(player, FALSE);
2020 case GST_MESSAGE_NEW_CLOCK:
2022 GstClock *clock = NULL;
2023 gst_message_parse_new_clock(msg, &clock);
2024 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2028 case GST_MESSAGE_ELEMENT:
2029 __mmplayer_gst_handle_element_message(player, msg);
2032 case GST_MESSAGE_DURATION_CHANGED:
2034 LOGD("GST_MESSAGE_DURATION_CHANGED");
2035 if (!__mmplayer_gst_handle_duration(player, msg))
2036 LOGW("failed to update duration");
2040 case GST_MESSAGE_ASYNC_START:
2041 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2044 case GST_MESSAGE_ASYNC_DONE:
2045 __mmplayer_gst_handle_async_done_message(player, msg);
2047 case GST_MESSAGE_STREAM_COLLECTION:
2049 GstStreamCollection *collection = NULL;
2050 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2052 gst_message_parse_stream_collection(msg, &collection);
2054 __mmplayer_dump_collection(collection);
2055 if (player->collection && player->stream_notify_id) {
2056 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2057 player->stream_notify_id = 0;
2059 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2060 if (player->collection) {
2061 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2062 (GCallback)__mmplayer_stream_notify_cb, player);
2064 gst_object_unref(collection);
2067 case GST_MESSAGE_STREAMS_SELECTED:
2069 GstStreamCollection *collection = NULL;
2070 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2072 gst_message_parse_streams_selected(msg, &collection);
2074 guint i = 0, len = 0;
2075 len = gst_message_streams_selected_get_size(msg);
2076 for (i = 0; i < len; i++) {
2077 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2078 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2079 gst_object_unref(stream);
2081 gst_object_unref (collection);
2086 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2087 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2088 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2089 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2090 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2091 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2092 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2093 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2094 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2095 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2096 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2097 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2098 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2099 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2100 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2107 /* should not call 'gst_message_unref(msg)' */
2111 static GstBusSyncReply
2112 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2114 mmplayer_t *player = (mmplayer_t *)data;
2115 GstBusSyncReply reply = GST_BUS_DROP;
2117 if (!(player->pipeline && player->pipeline->mainbin)) {
2118 LOGE("player pipeline handle is null");
2119 return GST_BUS_PASS;
2122 if (!__mmplayer_gst_check_useful_message(player, message)) {
2123 gst_message_unref(message);
2124 return GST_BUS_DROP;
2127 switch (GST_MESSAGE_TYPE(message)) {
2128 case GST_MESSAGE_TAG:
2129 __mmplayer_gst_extract_tag_from_msg(player, message);
2133 GstTagList *tags = NULL;
2135 gst_message_parse_tag(message, &tags);
2137 LOGE("TAGS received from element \"%s\".",
2138 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2140 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2141 gst_tag_list_unref(tags);
2149 case GST_MESSAGE_DURATION_CHANGED:
2150 __mmplayer_gst_handle_duration(player, message);
2152 case GST_MESSAGE_ELEMENT:
2154 const gchar *klass = NULL;
2155 klass = gst_element_factory_get_metadata
2156 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2157 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2158 reply = GST_BUS_PASS;
2161 __mmplayer_gst_handle_element_message(player, message);
2164 case GST_MESSAGE_ASYNC_DONE:
2165 /* NOTE:Don't call gst_callback directly
2166 * because previous frame can be showed even though this message is received for seek.
2169 reply = GST_BUS_PASS;
2173 if (reply == GST_BUS_DROP)
2174 gst_message_unref(message);
2180 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2182 GstElement *appsrc = element;
2183 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2184 GstBuffer *buffer = NULL;
2185 GstFlowReturn ret = GST_FLOW_OK;
2188 MMPLAYER_RETURN_IF_FAIL(element);
2189 MMPLAYER_RETURN_IF_FAIL(buf);
2191 buffer = gst_buffer_new();
2193 if (buf->offset < 0 || buf->len < 0) {
2194 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2198 if (buf->offset >= buf->len) {
2199 LOGD("call eos appsrc");
2200 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2204 if (buf->len - buf->offset < size)
2205 len = buf->len - buf->offset;
2207 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2208 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2209 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2212 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2214 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2220 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2222 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2224 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2226 buf->offset = (int)size;
2232 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2234 mmplayer_t *player = (mmplayer_t *)user_data;
2235 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2236 MMMessageParamType msg_param = {0,};
2237 guint64 current_level_bytes = 0;
2239 MMPLAYER_RETURN_IF_FAIL(player);
2241 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2242 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2243 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2244 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2246 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2250 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2252 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2254 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2255 msg_param.buffer_status.stream_type = stream_type;
2256 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2257 msg_param.buffer_status.bytes = current_level_bytes;
2259 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2263 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2265 mmplayer_t *player = (mmplayer_t *)user_data;
2266 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2267 MMMessageParamType msg_param = {0,};
2268 guint64 current_level_bytes = 0;
2270 MMPLAYER_RETURN_IF_FAIL(player);
2272 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2273 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2274 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2275 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2277 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2281 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2283 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2285 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2286 msg_param.buffer_status.stream_type = stream_type;
2287 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2288 msg_param.buffer_status.bytes = current_level_bytes;
2290 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2294 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2296 mmplayer_t *player = (mmplayer_t *)user_data;
2297 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2298 MMMessageParamType msg_param = {0,};
2300 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2302 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2303 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2304 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2305 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2307 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2311 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2313 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2314 msg_param.seek_data.stream_type = stream_type;
2315 msg_param.seek_data.offset = position;
2317 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2323 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2325 #define MAX_LEN_NAME 20
2327 gboolean ret = FALSE;
2328 GstPad *sinkpad = NULL;
2329 gchar *prefix = NULL;
2330 gchar dec_name[MAX_LEN_NAME] = {0, };
2331 main_element_id_e elem_id = MMPLAYER_M_NUM;
2333 mmplayer_gst_element_t *mainbin = NULL;
2334 GstElement *decodebin = NULL;
2335 GstCaps *dec_caps = NULL;
2339 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2341 player->pipeline->mainbin, FALSE);
2342 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2344 mainbin = player->pipeline->mainbin;
2346 case MM_PLAYER_STREAM_TYPE_AUDIO:
2348 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2350 case MM_PLAYER_STREAM_TYPE_VIDEO:
2352 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2355 LOGE("invalid type %d", type);
2359 if (mainbin[elem_id].gst) {
2360 LOGE("elem(%d) is already created", elem_id);
2364 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2366 /* create decodebin */
2367 decodebin = gst_element_factory_make("decodebin", dec_name);
2369 LOGE("failed to create %s", dec_name);
2373 /* raw pad handling signal */
2374 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2375 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2377 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2378 before looking for any elements that can handle that stream.*/
2379 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2380 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2382 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2383 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2384 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2386 /* This signal is emitted when a element is added to the bin.*/
2387 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2388 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2390 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2391 LOGE("failed to add new decodebin");
2395 dec_caps = gst_pad_query_caps(srcpad, NULL);
2398 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2400 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2401 gst_caps_unref(dec_caps);
2404 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2406 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2407 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2410 gst_object_unref(GST_OBJECT(sinkpad));
2412 gst_element_sync_state_with_parent(decodebin);
2414 mainbin[elem_id].id = elem_id;
2415 mainbin[elem_id].gst = decodebin;
2422 gst_object_unref(GST_OBJECT(sinkpad));
2425 gst_element_set_state(decodebin, GST_STATE_NULL);
2426 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2427 gst_object_unref(decodebin);
2435 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2437 #define MAX_LEN_NAME 20
2438 mmplayer_gst_element_t *mainbin = NULL;
2439 gchar *prefix = NULL;
2440 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2442 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2443 GstElement *src = NULL, *queue = NULL;
2444 GstPad *srcpad = NULL;
2447 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2448 player->pipeline->mainbin, FALSE);
2450 mainbin = player->pipeline->mainbin;
2452 LOGD("type(%d) path is creating", type);
2454 case MM_PLAYER_STREAM_TYPE_AUDIO:
2456 if (mainbin[MMPLAYER_M_SRC].gst)
2457 src_id = MMPLAYER_M_2ND_SRC;
2459 src_id = MMPLAYER_M_SRC;
2460 queue_id = MMPLAYER_M_A_BUFFER;
2462 case MM_PLAYER_STREAM_TYPE_VIDEO:
2464 src_id = MMPLAYER_M_SRC;
2465 queue_id = MMPLAYER_M_V_BUFFER;
2467 case MM_PLAYER_STREAM_TYPE_TEXT:
2468 prefix = "subtitle";
2469 src_id = MMPLAYER_M_SUBSRC;
2470 queue_id = MMPLAYER_M_S_BUFFER;
2473 LOGE("invalid type %d", type);
2477 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2478 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2481 src = gst_element_factory_make("appsrc", src_name);
2483 LOGF("failed to create %s", src_name);
2487 mainbin[src_id].id = src_id;
2488 mainbin[src_id].gst = src;
2490 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2491 "caps", caps, NULL);
2493 /* size of many video frames are larger than default blocksize as 4096 */
2494 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2495 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2497 if (player->media_stream_buffer_max_size[type] > 0)
2498 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2500 if (player->media_stream_buffer_min_percent[type] > 0)
2501 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2503 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2504 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2506 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2507 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2508 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2509 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2510 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2511 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2514 queue = gst_element_factory_make("queue2", queue_name);
2516 LOGE("failed to create %s", queue_name);
2519 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2521 mainbin[queue_id].id = queue_id;
2522 mainbin[queue_id].gst = queue;
2524 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2525 LOGE("failed to add src");
2529 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2530 LOGE("failed to add queue");
2534 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2535 LOGE("failed to link src and queue");
2539 /* create decoder */
2540 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2542 LOGE("failed to get srcpad of queue");
2546 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2547 _mmplayer_gst_create_decoder(player, srcpad, caps);
2549 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2550 LOGE("failed to create decoder");
2551 gst_object_unref(GST_OBJECT(srcpad));
2555 gst_object_unref(GST_OBJECT(srcpad));
2559 if (mainbin[src_id].gst) {
2560 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2561 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2562 gst_object_unref(mainbin[src_id].gst);
2563 mainbin[src_id].gst = NULL;
2566 if (mainbin[queue_id].gst) {
2567 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2568 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2569 gst_object_unref(mainbin[queue_id].gst);
2570 mainbin[queue_id].gst = NULL;
2577 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2579 GstPad *sinkpad = NULL;
2580 GstCaps *caps = NULL;
2581 GstElement *new_element = NULL;
2582 GstStructure *str = NULL;
2583 const gchar *name = NULL;
2585 mmplayer_t *player = (mmplayer_t *)data;
2589 MMPLAYER_RETURN_IF_FAIL(element && pad);
2590 MMPLAYER_RETURN_IF_FAIL(player &&
2592 player->pipeline->mainbin);
2594 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2595 * num_dynamic_pad will decreased after creating a sinkbin.
2597 player->num_dynamic_pad++;
2598 LOGD("stream count inc : %d", player->num_dynamic_pad);
2600 caps = gst_pad_query_caps(pad, NULL);
2601 MMPLAYER_CHECK_NULL(caps);
2603 str = gst_caps_get_structure(caps, 0);
2604 name = gst_structure_get_string(str, "media");
2606 LOGE("cannot get mimetype from structure.");
2610 if (strstr(name, "video")) {
2612 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2614 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2615 if (player->v_stream_caps) {
2616 gst_caps_unref(player->v_stream_caps);
2617 player->v_stream_caps = NULL;
2620 new_element = gst_element_factory_make("fakesink", NULL);
2621 player->num_dynamic_pad--;
2626 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2627 LOGE("failed to autoplug for caps");
2631 gst_caps_unref(caps);
2636 /* execute new_element if created*/
2638 LOGD("adding new element to pipeline");
2640 /* set state to READY before add to bin */
2641 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2643 /* add new element to the pipeline */
2644 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2645 LOGE("failed to add autoplug element to bin");
2649 /* get pad from element */
2650 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2652 LOGE("failed to get sinkpad from autoplug element");
2657 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2658 LOGE("failed to link autoplug element");
2662 gst_object_unref(sinkpad);
2665 /* run. setting PLAYING here since streaming source is live source */
2666 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2670 gst_caps_unref(caps);
2676 STATE_CHANGE_FAILED:
2678 /* FIXIT : take care if new_element has already added to pipeline */
2680 gst_object_unref(GST_OBJECT(new_element));
2683 gst_object_unref(GST_OBJECT(sinkpad));
2686 gst_caps_unref(caps);
2688 /* FIXIT : how to inform this error to MSL ????? */
2689 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2690 * then post an error to application
2695 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2697 mmplayer_t *player = (mmplayer_t *)data;
2701 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2702 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2703 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2704 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2706 * [1] audio and video will be dumped with filesink.
2707 * [2] autoplugging is done by just using pad caps.
2708 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2709 * and the video will be dumped via filesink.
2711 if (player->num_dynamic_pad == 0) {
2712 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2714 if (!_mmplayer_gst_remove_fakesink(player,
2715 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2716 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2717 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2718 * source element are not same. To overcome this situation, this function will called
2719 * several places and several times. Therefore, this is not an error case.
2724 /* create dot before error-return. for debugging */
2725 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2727 player->no_more_pad = TRUE;
2733 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2735 GstElement *element = NULL;
2736 gchar *user_agent = NULL;
2737 MMHandleType attrs = 0;
2740 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2742 /* get profile attribute */
2743 attrs = MMPLAYER_GET_ATTRS(player);
2745 LOGE("failed to get content attribute");
2749 element = gst_element_factory_make("rtspsrc", "rtsp source");
2751 LOGE("failed to create rtspsrc element");
2756 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2758 SECURE_LOGD("user_agent : %s", user_agent);
2760 /* setting property to streaming source */
2761 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2763 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2765 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2766 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2767 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2768 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2774 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2776 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2778 mmplayer_t *player = (mmplayer_t *)data;
2779 MMHandleType attrs = 0;
2780 gchar *user_agent, *cookies, **cookie_list;
2781 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2782 user_agent = cookies = NULL;
2786 MMPLAYER_RETURN_IF_FAIL(player);
2788 LOGD("source element %s", GST_ELEMENT_NAME(source));
2790 attrs = MMPLAYER_GET_ATTRS(player);
2792 LOGE("failed to get content attribute");
2796 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2797 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2799 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2800 http_timeout = player->ini.http_timeout;
2802 SECURE_LOGD("cookies : %s", cookies);
2803 SECURE_LOGD("user_agent : %s", user_agent);
2804 LOGD("timeout : %d", http_timeout);
2806 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2808 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2809 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2810 g_strfreev(cookie_list);
2814 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2820 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2822 mmplayer_t *player = (mmplayer_t *)data;
2823 gchar *user_agent = NULL;
2824 MMHandleType attrs = 0;
2827 MMPLAYER_RETURN_IF_FAIL(player);
2829 attrs = MMPLAYER_GET_ATTRS(player);
2831 LOGE("failed to get content attribute");
2835 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2837 SECURE_LOGD("user_agent : %s", user_agent);
2840 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2846 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2848 mmplayer_t *player = (mmplayer_t *)data;
2849 GstElement *source = NULL;
2852 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2854 g_object_get(orig, pspec->name, &source, NULL);
2856 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2857 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2859 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2860 __mmplayer_http_src_setup(source, data);
2861 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2862 __mmplayer_rtsp_src_setup(source, data);
2863 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2864 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2865 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2866 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2867 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2869 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2870 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2871 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2872 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2874 gst_object_unref (source);
2880 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
2882 const gchar *stream1_id = gst_stream_get_stream_id((GstStream *)stream1);
2883 const gchar *stream2_id = gst_stream_get_stream_id((GstStream *)stream2);
2885 return (g_strcmp0(stream1_id, stream2_id) == 0);
2889 __mmplayer_has_duplicated_stream(mmplayer_t *player, GstStreamType stype, GstStream *stream)
2891 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2893 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2896 case GST_STREAM_TYPE_AUDIO:
2897 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2899 case GST_STREAM_TYPE_VIDEO:
2900 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2902 case GST_STREAM_TYPE_TEXT:
2903 type = MM_PLAYER_TRACK_TYPE_TEXT;
2906 LOGD("Skip not supported stream stype");
2910 return g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL);
2914 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2915 GstStream * stream, gpointer data)
2917 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2918 GstStreamType stype = gst_stream_get_stream_type(stream);
2919 mmplayer_t *player = (mmplayer_t *)data;
2920 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2921 GstCaps *caps = gst_stream_get_caps(stream);
2922 GstStructure *caps_structure = NULL;
2923 gchar *caps_str = NULL;
2925 LOGD("Stream type %s flags 0x%x",
2926 gst_stream_type_get_name(stype),
2927 gst_stream_get_stream_flags(stream));
2928 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2930 if (__mmplayer_has_duplicated_stream(player, stype, stream)) {
2931 LOGD("Already added stream, skip it");
2937 caps_str = gst_caps_to_string(caps);
2938 caps_structure = gst_caps_get_structure(caps, 0);
2939 const gchar *mime = gst_structure_get_name(caps_structure);
2941 LOGD(" caps: %s", caps_str);
2943 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2944 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2945 LOGW("skip [%s] by unsupported codec keyword [%s]",
2946 mime, player->ini.unsupported_codec_keyword[idx]);
2948 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2956 case GST_STREAM_TYPE_AUDIO:
2958 gint samplerate = 0;
2961 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2963 if (caps_structure) {
2964 gst_structure_get_int(caps_structure, "rate", &samplerate);
2965 gst_structure_get_int(caps_structure, "channels", &channels);
2967 if (channels > 0 && samplerate == 0) {
2968 LOGW("Skip corrupted audio stream");
2972 if (g_strrstr(caps_str, "mobile-xmf"))
2973 mm_player_set_attribute((MMHandleType)player, NULL,
2974 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2978 case GST_STREAM_TYPE_VIDEO:
2983 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2985 /* do not support multi track video */
2986 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2989 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2991 /* don't make video because of not required */
2992 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2993 (!player->set_mode.video_export)) {
2994 LOGD("no need video decoding, skip video stream");
2998 if (caps_structure) {
2999 gst_structure_get_int(caps_structure, "width", &width);
3002 if (player->v_stream_caps) {
3003 gst_caps_unref(player->v_stream_caps);
3004 player->v_stream_caps = NULL;
3007 player->v_stream_caps = gst_caps_copy(caps);
3008 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3013 case GST_STREAM_TYPE_TEXT:
3014 type = MM_PLAYER_TRACK_TYPE_TEXT;
3017 LOGW("Skip not supported stream type");
3021 _mmplayer_track_update_stream(player, type, stream);
3023 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3024 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3025 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3026 _mmplayer_set_audio_attrs(player, caps);
3033 gst_caps_unref(caps);
3035 LOGD("ret %d", ret);
3040 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3041 GstStream * stream, gpointer data)
3043 mmplayer_t *player = (mmplayer_t *)data;
3044 GstStreamType stype = gst_stream_get_stream_type(stream);
3047 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3049 LOGD("stream type %s", gst_stream_type_get_name(stype));
3051 /* public does not support audio hw decoder at the moment */
3053 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3054 LOGW("video decoder resource is already acquired, skip it.");
3058 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3059 LOGE("failed to acquire video decoder resource");
3062 player->interrupted_by_resource = FALSE;
3068 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3070 GstIterator *iter = NULL;
3071 GValue item = {0, };
3072 GstElement *ch_element = NULL;
3073 GstElementFactory *ch_factory = NULL;
3076 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3078 iter = gst_bin_iterate_recurse(bin);
3079 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3081 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3082 ch_element = g_value_get_object(&item);
3083 ch_factory = gst_element_get_factory(ch_element);
3084 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3085 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3086 LOGD("Find %s element", element_name);
3090 g_value_reset(&item);
3092 gst_iterator_free(iter);
3098 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3100 mmplayer_t *player = (mmplayer_t *)data;
3102 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3104 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3105 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3106 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3108 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3109 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3110 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3113 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3115 mmplayer_t *player = (mmplayer_t *)data;
3116 int video_codec_type = 0;
3117 int audio_codec_type = 0;
3119 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3121 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3122 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3124 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3126 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3127 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3128 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3129 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3131 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3132 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3136 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3138 gchar *factory_name = NULL;
3139 mmplayer_t *player = (mmplayer_t *)data;
3142 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3144 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3146 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3148 if (g_strrstr(factory_name, "urisourcebin")) {
3149 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3151 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3153 LOGW("failed to find decodebin3");
3154 } else if (g_strrstr(factory_name, "parsebin")) {
3155 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3156 __mmplayer_parsebin_setup(GST_BIN(element), data);
3158 _mmplayer_gst_element_added(child, element, data);
3163 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3167 MMPLAYER_RETURN_IF_FAIL(player);
3168 MMPLAYER_RETURN_IF_FAIL(removed_element);
3170 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3172 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3173 GList *node = player->signals[type];
3175 GList *next_node = node->next;
3176 mmplayer_signal_item_t *item = node->data;
3177 if (item && item->obj == G_OBJECT(removed_element)) {
3178 player->signals[type] = g_list_delete_link(player->signals[type], node);
3179 MMPLAYER_FREEIF(item);
3189 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3191 mmplayer_t *player = (mmplayer_t *)data;
3195 MMPLAYER_RETURN_IF_FAIL(player);
3197 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3199 __mmplayer_delete_signal_connection(player, element);
3205 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3207 GstElement *uridecodebin3 = NULL;
3210 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3212 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3213 if (!uridecodebin3) {
3214 LOGE("failed to create uridecodebin3");
3219 SECURE_LOGD("uri : %s", player->profile.uri);
3221 /* setting property to streaming source */
3222 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3223 "message-forward", TRUE,
3224 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3225 "use-buffering", TRUE, NULL);
3227 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3228 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3230 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3231 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3233 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3234 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3236 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3237 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3239 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3240 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3242 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3245 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3248 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3251 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3252 LOGW("[DASH] this is still experimental feature");
3255 return uridecodebin3;
3259 __mmplayer_gst_make_http_src(mmplayer_t *player)
3261 #define MAX_RETRY_COUNT 10
3262 GstElement *element = NULL;
3263 MMHandleType attrs = 0;
3264 gchar *user_agent, *cookies, **cookie_list;
3265 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3267 user_agent = cookies = NULL;
3271 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3273 /* get profile attribute */
3274 attrs = MMPLAYER_GET_ATTRS(player);
3276 LOGE("failed to get content attribute");
3280 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3282 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3284 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3289 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3290 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3292 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3293 http_timeout = player->ini.http_timeout;
3296 SECURE_LOGD("location : %s", player->profile.uri);
3297 SECURE_LOGD("cookies : %s", cookies);
3298 SECURE_LOGD("user_agent : %s", user_agent);
3299 LOGD("timeout : %d", http_timeout);
3301 /* setting property to streaming source */
3302 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3303 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3304 "retries", MAX_RETRY_COUNT, NULL);
3306 /* parsing cookies */
3307 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3308 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3309 g_strfreev(cookie_list);
3313 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3315 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3316 LOGW("[DASH] this is still experimental feature");
3323 __mmplayer_gst_make_file_src(mmplayer_t *player)
3325 GstElement *element = NULL;
3328 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3330 LOGD("using filesrc for 'file://' handler");
3331 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3332 LOGE("failed to get storage info");
3336 element = gst_element_factory_make("filesrc", "source");
3338 LOGE("failed to create filesrc");
3342 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3349 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3351 mmplayer_t *player = (mmplayer_t *)data;
3353 g_return_val_if_fail(player, FALSE);
3354 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3355 gst_message_ref(msg);
3357 g_mutex_lock(&player->bus_msg_q_lock);
3358 g_queue_push_tail(player->bus_msg_q, msg);
3359 g_mutex_unlock(&player->bus_msg_q_lock);
3361 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3362 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3363 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3367 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3369 mmplayer_t *player = (mmplayer_t *)(data);
3370 GstMessage *msg = NULL;
3373 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3375 player->pipeline->mainbin &&
3376 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3379 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3381 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3382 while (!player->bus_msg_thread_exit) {
3383 g_mutex_lock(&player->bus_msg_q_lock);
3384 msg = g_queue_pop_head(player->bus_msg_q);
3385 g_mutex_unlock(&player->bus_msg_q_lock);
3387 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3390 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3391 /* handle the gst msg */
3392 __mmplayer_gst_bus_msg_callback(msg, player);
3393 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3394 gst_message_unref(msg);
3397 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3404 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3406 gint64 dur_nsec = 0;
3407 gint64 pos_nsec = 0;
3410 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3412 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3413 return MM_ERROR_NONE;
3415 /* NOTE : duration cannot be zero except live streaming.
3416 * Since some element could have some timing problem with querying duration, try again.
3418 if (player->duration == 0) {
3419 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3420 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3421 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3422 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3423 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3424 player->pending_seek.is_pending = true;
3425 player->pending_seek.pos = position;
3426 player->seek_state = MMPLAYER_SEEK_NONE;
3427 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3428 return MM_ERROR_PLAYER_NO_OP;
3430 player->seek_state = MMPLAYER_SEEK_NONE;
3431 return MM_ERROR_PLAYER_SEEK;
3434 player->duration = dur_nsec;
3437 if (player->duration > 0 && player->duration < position) {
3438 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3439 return MM_ERROR_INVALID_ARGUMENT;
3442 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3443 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3444 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3445 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3446 player->seek_state = MMPLAYER_SEEK_NONE;
3447 return MM_ERROR_PLAYER_NO_OP;
3452 return MM_ERROR_NONE;
3456 __mmplayer_gst_check_seekable(mmplayer_t *player)
3458 GstQuery *query = NULL;
3459 gboolean seekable = FALSE;
3461 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3465 query = gst_query_new_seeking(GST_FORMAT_TIME);
3466 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3467 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3468 gst_query_unref(query);
3471 LOGW("non-seekable content");
3472 player->seek_state = MMPLAYER_SEEK_NONE;
3476 LOGW("failed to get seeking query");
3477 gst_query_unref(query); /* keep seeking operation */
3484 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3486 GstState element_state = GST_STATE_VOID_PENDING;
3487 GstState element_pending_state = GST_STATE_VOID_PENDING;
3488 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3492 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3493 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3495 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3498 ret = gst_element_set_state(element, state);
3499 if (ret == GST_STATE_CHANGE_FAILURE) {
3500 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3502 /* dump state of all element */
3503 _mmplayer_dump_pipeline_state(player);
3505 return MM_ERROR_PLAYER_INTERNAL;
3508 /* return here so state transition to be done in async mode */
3510 LOGD("async state transition. not waiting for state complete.");
3511 return MM_ERROR_NONE;
3514 /* wait for state transition */
3515 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3516 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3517 LOGE("failed to change [%s] element state to [%s] within %d sec",
3518 GST_ELEMENT_NAME(element),
3519 gst_element_state_get_name(state), timeout);
3521 LOGE(" [%s] state : %s pending : %s",
3522 GST_ELEMENT_NAME(element),
3523 gst_element_state_get_name(element_state),
3524 gst_element_state_get_name(element_pending_state));
3526 /* dump state of all element */
3527 _mmplayer_dump_pipeline_state(player);
3529 return MM_ERROR_PLAYER_INTERNAL;
3532 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3536 return MM_ERROR_NONE;
3540 _mmplayer_gst_start(mmplayer_t *player)
3542 int ret = MM_ERROR_NONE;
3543 gboolean async = FALSE;
3547 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3549 /* NOTE : if SetPosition was called before Start. do it now
3550 * streaming doesn't support it. so it should be always sync
3551 * !!create one more api to check if there is pending seek rather than checking variables
3553 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3554 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3555 ret = _mmplayer_gst_pause(player, FALSE);
3556 if (ret != MM_ERROR_NONE) {
3557 LOGE("failed to set state to PAUSED for pending seek");
3561 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3562 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3563 LOGW("failed to seek pending position. starting from the begin of content");
3566 LOGD("current state before doing transition");
3567 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3568 MMPLAYER_PRINT_STATE(player);
3570 /* set pipeline state to PLAYING */
3571 ret = _mmplayer_gst_set_state(player,
3572 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3573 if (ret != MM_ERROR_NONE) {
3574 LOGE("failed to set state to PLAYING");
3578 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3580 /* generating debug info before returning error */
3581 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3589 _mmplayer_gst_stop(mmplayer_t *player)
3591 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3592 MMHandleType attrs = 0;
3593 gboolean rewind = FALSE;
3595 int ret = MM_ERROR_NONE;
3599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3600 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3602 LOGD("current state before doing transition");
3603 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3604 MMPLAYER_PRINT_STATE(player);
3606 attrs = MMPLAYER_GET_ATTRS(player);
3608 LOGE("cannot get content attribute");
3609 return MM_ERROR_PLAYER_INTERNAL;
3612 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3613 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3615 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3616 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3619 if (player->es_player_push_mode)
3620 /* disable the async state transition because there could be no data in the pipeline */
3621 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3624 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3626 if (player->es_player_push_mode) {
3627 /* enable the async state transition as default operation */
3628 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3631 /* return if set_state has failed */
3632 if (ret != MM_ERROR_NONE) {
3633 LOGE("failed to set state.");
3639 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3640 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3641 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3642 LOGW("failed to rewind");
3643 ret = MM_ERROR_PLAYER_SEEK;
3648 player->sent_bos = FALSE;
3650 if (player->es_player_push_mode) //for cloudgame
3653 /* wait for seek to complete */
3654 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3655 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3656 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3658 LOGE("fail to stop player.");
3659 ret = MM_ERROR_PLAYER_INTERNAL;
3660 _mmplayer_dump_pipeline_state(player);
3663 /* generate dot file if enabled */
3664 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3672 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3674 int ret = MM_ERROR_NONE;
3678 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3679 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3681 LOGD("current state before doing transition");
3682 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3683 MMPLAYER_PRINT_STATE(player);
3685 /* set pipeline status to PAUSED */
3686 ret = _mmplayer_gst_set_state(player,
3687 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3692 if (ret != MM_ERROR_NONE) {
3693 GstMessage *msg = NULL;
3694 GTimer *timer = NULL;
3695 gdouble MAX_TIMEOUT_SEC = 3;
3697 LOGE("failed to set state to PAUSED");
3699 if (!player->bus_watcher) {
3700 LOGE("there is no bus msg thread. pipeline is shutting down.");
3704 if (player->msg_posted) {
3705 LOGE("error msg is already posted.");
3709 timer = g_timer_new();
3710 g_timer_start(timer);
3712 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3715 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3717 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3718 GError *error = NULL;
3720 /* parse error code */
3721 gst_message_parse_error(msg, &error, NULL);
3723 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3724 /* Note : the streaming error from the streaming source is handled
3725 * using __mmplayer_handle_streaming_error.
3727 __mmplayer_handle_streaming_error(player, msg, error);
3730 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3732 if (error->domain == GST_STREAM_ERROR)
3733 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3734 else if (error->domain == GST_RESOURCE_ERROR)
3735 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3736 else if (error->domain == GST_LIBRARY_ERROR)
3737 ret = __mmplayer_gst_handle_library_error(player, error->code);
3738 else if (error->domain == GST_CORE_ERROR)
3739 ret = __mmplayer_gst_handle_core_error(player, error->code);
3741 g_error_free(error);
3743 player->msg_posted = TRUE;
3745 gst_message_unref(msg);
3747 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3749 gst_object_unref(bus);
3750 g_timer_stop(timer);
3751 g_timer_destroy(timer);
3756 if (MMPLAYER_USE_DECODEBIN(player)) {
3757 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3758 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3759 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3762 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3765 /* generate dot file before returning error */
3766 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3774 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3776 int ret = MM_ERROR_NONE;
3781 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3782 MM_ERROR_PLAYER_NOT_INITIALIZED);
3784 LOGD("current state before doing transition");
3785 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3786 MMPLAYER_PRINT_STATE(player);
3789 LOGD("do async state transition to PLAYING");
3791 /* set pipeline state to PLAYING */
3792 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3794 ret = _mmplayer_gst_set_state(player,
3795 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3796 if (ret != MM_ERROR_NONE) {
3797 LOGE("failed to set state to PLAYING");
3802 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3805 /* generate dot file */
3806 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3813 /* sending event to one of sinkelements */
3815 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3817 GstEvent *event2 = NULL;
3818 GList *sinks = NULL;
3819 gboolean res = FALSE;
3822 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3823 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3825 /* While adding subtitles in live feeds seek is getting called.
3826 Adding defensive check in framework layer.*/
3827 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3828 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3829 LOGE("Should not send seek event during live playback");
3834 if (player->play_subtitle)
3835 event2 = gst_event_copy((const GstEvent *)event);
3837 sinks = player->sink_elements;
3839 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3841 if (GST_IS_ELEMENT(sink)) {
3842 /* keep ref to the event */
3843 gst_event_ref(event);
3845 if ((res = gst_element_send_event(sink, event))) {
3846 LOGD("sending event[%s] to sink element [%s] success!",
3847 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3849 /* rtsp case, async_done is not called after seek during pause state */
3850 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3851 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3852 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3853 LOGD("RTSP seek completed, after pause state..");
3854 player->seek_state = MMPLAYER_SEEK_NONE;
3855 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3861 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3862 sinks = g_list_next(sinks);
3869 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3870 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3873 sinks = g_list_next(sinks);
3876 /* Note : Textbin is not linked to the video or audio bin.
3877 * It needs to send the event to the text sink separately.
3879 if (player->play_subtitle && player->pipeline) {
3880 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3882 if (GST_IS_ELEMENT(text_sink)) {
3883 /* keep ref to the event */
3884 gst_event_ref(event2);
3886 if ((res = gst_element_send_event(text_sink, event2)))
3887 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3888 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3890 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3891 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3893 gst_event_unref(event2);
3897 gst_event_unref(event);
3905 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3906 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3907 gint64 cur, GstSeekType stop_type, gint64 stop)
3909 GstEvent *event = NULL;
3910 gboolean result = FALSE;
3914 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3916 if (player->pipeline && player->pipeline->textbin)
3917 __mmplayer_drop_subtitle(player, FALSE);
3919 event = gst_event_new_seek(rate, format, flags, cur_type,
3920 cur, stop_type, stop);
3922 result = _mmplayer_gst_send_event_to_sink(player, event);
3930 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3932 int ret = MM_ERROR_NONE;
3933 gint64 pos_nsec = 0;
3934 gboolean accurate = FALSE;
3935 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3938 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3939 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3941 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3942 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3945 ret = __mmplayer_gst_check_position(player, position);
3946 if (ret != MM_ERROR_NONE) {
3947 LOGW("result of check position info 0x%X", ret);
3948 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3951 if (!__mmplayer_gst_check_seekable(player))
3952 return MM_ERROR_PLAYER_NO_OP;
3954 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3955 position, player->playback_rate, player->duration);
3957 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3958 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3959 This causes problem is position calculation during normal pause resume scenarios also.
3960 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3961 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3962 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3963 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3964 LOGW("getting current position failed in seek");
3966 player->last_position = pos_nsec;
3967 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3970 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3971 LOGD("not completed seek");
3972 return MM_ERROR_PLAYER_DOING_SEEK;
3975 if (!internal_called)
3976 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3978 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3979 that's why set position through property. */
3980 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3981 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3982 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3983 (!player->videodec_linked) && (!player->audiodec_linked)) {
3985 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3986 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3988 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3989 player->seek_state = MMPLAYER_SEEK_NONE;
3990 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3992 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3994 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3996 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3998 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3999 GST_FORMAT_TIME, seek_flags,
4000 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4001 LOGE("failed to set position");
4006 /* NOTE : store last seeking point to overcome some bad operation
4007 * (returning zero when getting current position) of some elements
4009 player->last_position = position;
4011 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4012 if (player->playback_rate > 1.0)
4013 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4015 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4016 LOGD("buffering should be reset after seeking");
4017 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4018 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4022 return MM_ERROR_NONE;
4025 player->pending_seek.is_pending = true;
4026 player->pending_seek.pos = position;
4028 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4029 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4030 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4031 player->pending_seek.pos);
4033 return MM_ERROR_NONE;
4036 player->seek_state = MMPLAYER_SEEK_NONE;
4037 return MM_ERROR_PLAYER_SEEK;
4041 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4043 #define TRICKPLAY_OFFSET GST_MSECOND
4045 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4046 gint64 pos_nsec = 0;
4047 gboolean ret = TRUE;
4049 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4050 MM_ERROR_PLAYER_NOT_INITIALIZED);
4052 current_state = MMPLAYER_CURRENT_STATE(player);
4054 /* NOTE : query position except paused state to overcome some bad operation
4055 * please refer to below comments in details
4057 if (current_state != MM_PLAYER_STATE_PAUSED)
4058 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4060 /* NOTE : get last point to overcome some bad operation of some elements
4061 *(returning zero when getting current position in paused state
4062 * and when failed to get position during seeking
4064 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4065 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4067 if (player->playback_rate < 0.0)
4068 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4070 pos_nsec = player->last_position;
4073 pos_nsec = player->last_position;
4075 player->last_position = pos_nsec;
4077 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4080 if (player->duration > 0 && pos_nsec > player->duration)
4081 pos_nsec = player->duration;
4083 player->last_position = pos_nsec;
4086 *position = pos_nsec;
4088 return MM_ERROR_NONE;
4092 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4094 #define STREAMING_IS_FINISHED 0
4095 #define BUFFERING_MAX_PER 100
4096 #define DEFAULT_PER_VALUE -1
4097 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4099 mmplayer_gst_element_t *mainbin = NULL;
4100 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4101 gint64 buffered_total = 0;
4102 gint64 position = 0;
4103 gint buffered_sec = -1;
4104 GstBufferingMode mode = GST_BUFFERING_STREAM;
4105 gint64 content_size_time = player->duration;
4106 guint64 content_size_bytes = player->http_content_size;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4110 player->pipeline->mainbin,
4111 MM_ERROR_PLAYER_NOT_INITIALIZED);
4113 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4118 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4119 /* and rtsp is not ready yet. */
4120 LOGW("it's only used for http streaming case");
4121 return MM_ERROR_PLAYER_NO_OP;
4124 if (content_size_time <= 0 || content_size_bytes <= 0) {
4125 LOGW("there is no content size");
4126 return MM_ERROR_NONE;
4129 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4130 LOGW("fail to get current position");
4131 return MM_ERROR_NONE;
4134 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4135 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4137 mainbin = player->pipeline->mainbin;
4138 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4140 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4141 GstQuery *query = NULL;
4142 gint byte_in_rate = 0, byte_out_rate = 0;
4143 gint64 estimated_total = 0;
4145 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4146 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4147 LOGW("fail to get buffering query from queue2");
4149 gst_query_unref(query);
4150 return MM_ERROR_NONE;
4153 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4154 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4156 if (mode == GST_BUFFERING_STREAM) {
4157 /* using only queue in case of push mode(ts / mp3) */
4158 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4159 GST_FORMAT_BYTES, &buffered_total)) {
4160 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4161 end_per = 100 * buffered_total / content_size_bytes;
4164 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4166 guint num_of_ranges = 0;
4167 gint64 start_byte = 0, stop_byte = 0;
4169 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4170 if (estimated_total != STREAMING_IS_FINISHED) {
4171 /* buffered size info from queue2 */
4172 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4173 for (idx = 0; idx < num_of_ranges; idx++) {
4174 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4175 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4177 buffered_total += (stop_byte - start_byte);
4180 end_per = BUFFERING_MAX_PER;
4183 gst_query_unref(query);
4186 if (end_per == DEFAULT_PER_VALUE) {
4187 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4189 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4191 /* buffered size info from multiqueue */
4192 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4193 guint curr_size_bytes = 0;
4194 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4195 "curr-size-bytes", &curr_size_bytes, NULL);
4196 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4197 buffered_total += curr_size_bytes;
4200 if (avg_byterate > 0)
4201 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4202 else if (player->total_maximum_bitrate > 0)
4203 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4204 else if (player->total_bitrate > 0)
4205 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4207 if (buffered_sec >= 0)
4208 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4212 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4213 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4215 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4216 buffered_total, buffered_sec, *start_pos, *end_pos);
4218 return MM_ERROR_NONE;
4222 _mmplayer_gst_create_source(mmplayer_t *player)
4224 GstElement *element = NULL;
4227 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4228 player->pipeline->mainbin, NULL);
4230 /* setup source for gapless play */
4231 switch (player->profile.uri_type) {
4233 case MM_PLAYER_URI_TYPE_FILE:
4234 element = __mmplayer_gst_make_file_src(player);
4236 case MM_PLAYER_URI_TYPE_URL_HTTP:
4237 element = __mmplayer_gst_make_http_src(player);
4240 LOGE("not support uri type %d", player->profile.uri_type);
4245 LOGE("failed to create source element");
4254 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4257 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4258 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4260 SECURE_LOGD("uri : %s", player->profile.uri);
4262 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4264 if ((player->v_stream_caps) &&
4265 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4266 return MM_ERROR_PLAYER_INTERNAL;
4268 if ((player->a_stream_caps) &&
4269 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4270 return MM_ERROR_PLAYER_INTERNAL;
4272 if ((player->s_stream_caps) &&
4273 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4274 return MM_ERROR_PLAYER_INTERNAL;
4277 return MM_ERROR_NONE;
4281 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4283 mmplayer_gst_element_t *mainbin = NULL;
4284 GstElement *autoplug_elem = NULL;
4287 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4288 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4290 mainbin = player->pipeline->mainbin;
4292 LOGD("uri type %d", player->profile.uri_type);
4294 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4295 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4296 return MM_ERROR_PLAYER_INTERNAL;
4299 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4300 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4303 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4304 if (!autoplug_elem) {
4305 LOGE("failed to create uridecodebin3 element");
4309 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4310 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4311 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4313 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4314 LOGE("failed to add uridecodebin to pipeline");
4318 /* FIXME: required ?*/
4319 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4320 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4321 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4323 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4324 LOGE("failed to create fakesink");
4327 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4329 /* take ownership of fakesink. we are reusing it */
4330 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4332 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4333 LOGE("failed to add fakesink to bin");
4334 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4339 return MM_ERROR_NONE;
4343 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4344 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4346 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4347 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4349 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4350 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4352 return MM_ERROR_PLAYER_INTERNAL;
4356 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4358 mmplayer_gst_element_t *mainbin = NULL;
4359 GstElement *src_elem = NULL;
4360 GstElement *autoplug_elem = NULL;
4361 GList *element_bucket = NULL;
4362 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4365 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4366 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4368 LOGD("uri type %d", player->profile.uri_type);
4370 /* create source element */
4371 switch (player->profile.uri_type) {
4372 case MM_PLAYER_URI_TYPE_URL_RTSP:
4373 src_elem = __mmplayer_gst_make_rtsp_src(player);
4375 case MM_PLAYER_URI_TYPE_URL_HTTP:
4376 src_elem = __mmplayer_gst_make_http_src(player);
4378 case MM_PLAYER_URI_TYPE_FILE:
4379 src_elem = __mmplayer_gst_make_file_src(player);
4381 case MM_PLAYER_URI_TYPE_SS:
4383 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4384 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4386 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4390 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4391 LOGD("get timeout from ini");
4392 http_timeout = player->ini.http_timeout;
4395 /* setting property to streaming source */
4396 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4399 case MM_PLAYER_URI_TYPE_MEM:
4401 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4403 src_elem = gst_element_factory_make("appsrc", "mem-source");
4405 LOGE("failed to create appsrc element");
4409 g_object_set(src_elem, "stream-type", stream_type,
4410 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4412 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4413 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4414 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4415 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4419 LOGE("not support uri type");
4424 LOGE("failed to create source element");
4425 return MM_ERROR_PLAYER_INTERNAL;
4428 mainbin = player->pipeline->mainbin;
4430 /* take source element */
4431 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4433 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4434 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4435 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4437 /* create next element for auto-plugging */
4438 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4439 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4440 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4441 if (!autoplug_elem) {
4442 LOGE("failed to create typefind element");
4446 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4447 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4448 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4449 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4450 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4451 if (!autoplug_elem) {
4452 LOGE("failed to create decodebin");
4456 /* default size of mq in decodebin is 2M
4457 * but it can cause blocking issue during seeking depends on content. */
4458 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4461 if (autoplug_elem) {
4462 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4463 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4464 mainbin[autoplug_elem_id].gst = autoplug_elem;
4466 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4469 /* add elements to pipeline */
4470 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4471 LOGE("failed to add elements to pipeline");
4475 /* linking elements in the bucket by added order. */
4476 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4477 LOGE("failed to link some elements");
4481 /* FIXME: need to check whether this is required or not. */
4482 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4483 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4484 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4485 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4486 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4488 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4489 LOGE("failed to create fakesink");
4492 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4494 /* take ownership of fakesink. we are reusing it */
4495 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4497 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4498 LOGE("failed to add fakesink to bin");
4499 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4504 g_list_free(element_bucket);
4507 return MM_ERROR_NONE;
4510 g_list_free(element_bucket);
4512 if (mainbin[MMPLAYER_M_SRC].gst)
4513 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4515 if (mainbin[autoplug_elem_id].gst)
4516 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4518 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4519 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4521 mainbin[MMPLAYER_M_SRC].gst = NULL;
4522 mainbin[autoplug_elem_id].gst = NULL;
4523 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4525 return MM_ERROR_PLAYER_INTERNAL;
4529 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4532 mmplayer_gst_element_t *mainbin = NULL;
4535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4536 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4538 mainbin = player->pipeline->mainbin;
4540 /* connect bus callback */
4541 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4543 LOGE("cannot get bus from pipeline");
4544 return MM_ERROR_PLAYER_INTERNAL;
4547 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4548 (GstBusFunc)__mmplayer_gst_msg_push, player,
4549 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4550 if (player->bus_watcher == 0) {
4551 LOGE("failed to add bus watch");
4552 return MM_ERROR_PLAYER_INTERNAL;
4555 g_mutex_init(&player->bus_watcher_mutex);
4556 g_cond_init(&player->bus_watcher_cond);
4558 player->context.thread_default = g_main_context_get_thread_default();
4559 if (player->context.thread_default == NULL) {
4560 player->context.thread_default = g_main_context_default();
4561 LOGD("thread-default context is the global default context");
4563 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4565 /* set sync handler to get tag synchronously */
4566 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4567 gst_object_unref(GST_OBJECT(bus));
4569 /* create gst bus_msb_cb thread */
4570 g_mutex_init(&player->bus_msg_thread_mutex);
4571 g_cond_init(&player->bus_msg_thread_cond);
4572 player->bus_msg_thread_exit = FALSE;
4573 player->bus_msg_thread =
4574 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4575 if (!player->bus_msg_thread) {
4576 LOGE("failed to create gst BUS msg thread");
4577 g_mutex_clear(&player->bus_msg_thread_mutex);
4578 g_cond_clear(&player->bus_msg_thread_cond);
4579 return MM_ERROR_PLAYER_INTERNAL;
4583 return MM_ERROR_NONE;
4587 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4589 int ret = MM_ERROR_NONE;
4590 mmplayer_gst_element_t *mainbin = NULL;
4591 MMMessageParamType msg_param = {0,};
4592 GstElement *element = NULL;
4593 MMHandleType attrs = 0;
4595 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4599 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4600 LOGE("player is not initialized");
4604 mainbin = player->pipeline->mainbin;
4605 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4607 attrs = MMPLAYER_GET_ATTRS(player);
4609 LOGE("fail to get attributes");
4613 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4615 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4616 LOGE("failed to parse profile");
4617 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4621 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4622 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4623 LOGE("dash or hls is not supportable");
4624 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4628 if (!MMPLAYER_USE_DECODEBIN(player)) {
4629 ret = _mmplayer_gst_build_pipeline_with_src(player);
4630 if (ret != MM_ERROR_NONE)
4633 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4634 LOGE("Failed to change state of uridecodebin3 element");
4640 element = _mmplayer_gst_create_source(player);
4642 LOGE("no source element was created");
4646 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4647 LOGE("failed to add source element to pipeline");
4648 gst_object_unref(GST_OBJECT(element));
4653 /* take source element */
4654 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4655 mainbin[MMPLAYER_M_SRC].gst = element;
4659 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4660 if (player->streamer == NULL) {
4661 player->streamer = _mm_player_streaming_create();
4662 _mm_player_streaming_initialize(player->streamer, TRUE);
4665 elem_idx = MMPLAYER_M_TYPEFIND;
4666 element = gst_element_factory_make("typefind", "typefinder");
4667 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4668 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4670 elem_idx = MMPLAYER_M_AUTOPLUG;
4671 element = _mmplayer_gst_make_decodebin(player);
4674 /* check autoplug element is OK */
4676 LOGE("can not create element(%d)", elem_idx);
4680 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4681 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4682 gst_object_unref(GST_OBJECT(element));
4687 mainbin[elem_idx].id = elem_idx;
4688 mainbin[elem_idx].gst = element;
4690 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4691 LOGE("Failed to link src - autoplug(or typefind)");
4695 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4696 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4697 LOGE("Failed to change state of src element");
4701 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4702 LOGE("Failed to change state of decodebin");
4707 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4708 LOGE("Failed to change state of src element");
4713 player->gapless.stream_changed = TRUE;
4714 player->gapless.running = TRUE;
4720 _mmplayer_set_reconfigure_state(player, FALSE);
4721 if (!player->msg_posted) {
4722 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4723 player->msg_posted = TRUE;