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 if (string == NULL) {\
770 LOGD("failed to get date/time from tag");\
774 mm_player_set_attribute((MMHandleType)player, NULL,\
775 playertag, string, strlen(string), NULL); \
776 SECURE_LOGD("metainfo year : %s", string);\
777 MMPLAYER_FREEIF(string);\
783 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
785 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
786 if (datetime != NULL) {\
787 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
788 if (string == NULL) {\
789 LOGD("failed to get year from tag");\
790 gst_date_time_unref(datetime);\
793 mm_player_set_attribute((MMHandleType)player, NULL,\
794 playertag, string, strlen(string), NULL); \
795 SECURE_LOGD("metainfo year : %s", string);\
796 MMPLAYER_FREEIF(string);\
797 gst_date_time_unref(datetime);\
803 GstTagList *tag_list = NULL;
808 GstDateTime *datetime = NULL;
810 GstBuffer *buffer = NULL;
812 MMMessageParamType msg_param = {0, };
814 /* currently not used. but those are needed for above macro */
815 //guint64 v_uint64 = 0;
816 //gdouble v_double = 0;
818 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
820 /* get tag list from gst message */
821 gst_message_parse_tag(msg, &tag_list);
823 /* store tags to player attributes */
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
826 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
827 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
828 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
829 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
830 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
831 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
832 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
833 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
834 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
835 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
836 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
837 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
838 MMPLAYER_UPDATE_TAG_LOCK(player);
839 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
840 MMPLAYER_UPDATE_TAG_UNLOCK(player);
841 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
843 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
844 if (player->video360_metadata.is_spherical == -1) {
845 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
846 mm_player_set_attribute((MMHandleType)player, NULL,
847 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
848 if (player->video360_metadata.is_spherical == 1) {
849 LOGD("This is spherical content for 360 playback.");
850 player->is_content_spherical = TRUE;
852 LOGD("This is not spherical content");
853 player->is_content_spherical = FALSE;
856 if (player->video360_metadata.projection_type_string) {
857 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
858 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
860 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
861 player->is_content_spherical = player->is_video360_enabled = FALSE;
865 if (player->video360_metadata.stereo_mode_string) {
866 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
867 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
868 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
869 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
870 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
871 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
873 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
874 player->is_content_spherical = player->is_video360_enabled = FALSE;
880 gst_tag_list_unref(tag_list);
886 static mmplayer_track_type_e
887 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
890 case GST_STREAM_TYPE_AUDIO:
891 return MM_PLAYER_TRACK_TYPE_AUDIO;
892 case GST_STREAM_TYPE_VIDEO:
893 return MM_PLAYER_TRACK_TYPE_VIDEO;
894 case GST_STREAM_TYPE_TEXT:
895 return MM_PLAYER_TRACK_TYPE_TEXT;
897 LOGD("not supported stream stype");
898 return MM_PLAYER_TRACK_TYPE_MAX;
902 /* if retval is FALSE, it will be dropped for performance. */
904 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
906 gboolean retval = FALSE;
908 if (!(player->pipeline && player->pipeline->mainbin)) {
909 LOGE("player pipeline handle is null");
913 switch (GST_MESSAGE_TYPE(message)) {
914 case GST_MESSAGE_TAG:
915 case GST_MESSAGE_EOS:
916 case GST_MESSAGE_ERROR:
917 case GST_MESSAGE_WARNING:
918 case GST_MESSAGE_CLOCK_LOST:
919 case GST_MESSAGE_NEW_CLOCK:
920 case GST_MESSAGE_ELEMENT:
921 case GST_MESSAGE_DURATION_CHANGED:
922 case GST_MESSAGE_ASYNC_START:
923 case GST_MESSAGE_STREAM_COLLECTION:
926 case GST_MESSAGE_ASYNC_DONE:
927 case GST_MESSAGE_STATE_CHANGED:
928 /* we only handle messages from pipeline */
929 MMPLAYER_RECONFIGURE_LOCK(player);
930 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
934 MMPLAYER_RECONFIGURE_UNLOCK(player);
936 case GST_MESSAGE_BUFFERING:
938 gint buffer_percent = 0;
941 gst_message_parse_buffering(message, &buffer_percent);
942 if (buffer_percent != MAX_BUFFER_PERCENT) {
943 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
947 if (!MMPLAYER_CMD_TRYLOCK(player)) {
948 LOGW("can't get cmd lock, send msg to bus");
952 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
953 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
954 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
957 MMPLAYER_CMD_UNLOCK(player);
961 case GST_MESSAGE_STREAMS_SELECTED:
963 if (MMPLAYER_USE_DECODEBIN(player))
964 break; /* drop msg */
966 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
967 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
968 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
970 gint64 dur_bytes = 0L;
972 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
973 LOGE("fail to get duration.");
975 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
976 * use file information was already set on Q2 when it was created. */
977 _mm_player_streaming_set_queue2(player->streamer,
978 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
979 TRUE, /* use_buffering */
980 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
981 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
984 LOGD("GST_MESSAGE_STREAMS_SELECTED");
985 player->no_more_pad = TRUE;
986 _mmplayer_set_reconfigure_state(player, FALSE);
987 if (!MMPLAYER_IS_ADAPTIVE_STREAMING(player))
988 _mmplayer_pipeline_complete(NULL, player);
1001 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1003 guint64 data_size = 0;
1004 gint64 pos_nsec = 0;
1006 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1008 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1010 if (MMPLAYER_IS_HTTP_STREAMING(player))
1011 data_size = player->http_content_size;
1013 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1014 if (!player->streamer->is_adaptive_streaming) {
1015 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1019 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1020 if (!player->streamer->buffering_req.is_pre_buffering) {
1021 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1022 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1023 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1029 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1031 int ret = MM_ERROR_NONE;
1032 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1033 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1034 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1035 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1037 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1038 LOGW("do nothing for buffering msg");
1039 ret = MM_ERROR_PLAYER_INVALID_STATE;
1043 prev_state = MMPLAYER_PREV_STATE(player);
1044 current_state = MMPLAYER_CURRENT_STATE(player);
1045 target_state = MMPLAYER_TARGET_STATE(player);
1046 pending_state = MMPLAYER_PENDING_STATE(player);
1048 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1049 MMPLAYER_STATE_GET_NAME(prev_state),
1050 MMPLAYER_STATE_GET_NAME(current_state),
1051 MMPLAYER_STATE_GET_NAME(pending_state),
1052 MMPLAYER_STATE_GET_NAME(target_state),
1053 player->streamer->buffering_state);
1055 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1056 /* NOTE : if buffering has done, player has to go to target state. */
1057 switch (target_state) {
1058 case MM_PLAYER_STATE_PAUSED:
1060 switch (pending_state) {
1061 case MM_PLAYER_STATE_PLAYING:
1062 _mmplayer_gst_pause(player, TRUE);
1065 case MM_PLAYER_STATE_PAUSED:
1066 LOGD("player is already going to paused state, there is nothing to do.");
1069 case MM_PLAYER_STATE_NONE:
1070 case MM_PLAYER_STATE_NULL:
1071 case MM_PLAYER_STATE_READY:
1073 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1079 case MM_PLAYER_STATE_PLAYING:
1081 switch (pending_state) {
1082 case MM_PLAYER_STATE_NONE:
1084 if (current_state != MM_PLAYER_STATE_PLAYING)
1085 _mmplayer_gst_resume(player, TRUE);
1089 case MM_PLAYER_STATE_PAUSED:
1090 /* NOTE: It should be worked as asynchronously.
1091 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1093 if (current_state == MM_PLAYER_STATE_PLAYING) {
1094 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1095 * The current state should be changed to paused purposely to prevent state conflict.
1097 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1099 _mmplayer_gst_resume(player, TRUE);
1102 case MM_PLAYER_STATE_PLAYING:
1103 LOGD("player is already going to playing state, there is nothing to do.");
1106 case MM_PLAYER_STATE_NULL:
1107 case MM_PLAYER_STATE_READY:
1109 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1115 case MM_PLAYER_STATE_NULL:
1116 case MM_PLAYER_STATE_READY:
1117 case MM_PLAYER_STATE_NONE:
1119 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1123 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1124 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1126 switch (pending_state) {
1127 case MM_PLAYER_STATE_NONE:
1129 if (current_state != MM_PLAYER_STATE_PAUSED) {
1130 /* rtsp streaming pause makes rtsp server stop sending data. */
1131 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1132 LOGD("set pause state during buffering");
1133 _mmplayer_gst_pause(player, TRUE);
1139 case MM_PLAYER_STATE_PLAYING:
1140 /* rtsp streaming pause makes rtsp server stop sending data. */
1141 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1142 _mmplayer_gst_pause(player, TRUE);
1145 case MM_PLAYER_STATE_PAUSED:
1148 case MM_PLAYER_STATE_NULL:
1149 case MM_PLAYER_STATE_READY:
1151 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1160 static stream_variant_t *
1161 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1163 stream_variant_t *var_info = NULL;
1164 g_return_val_if_fail(self != NULL, NULL);
1166 var_info = g_new0(stream_variant_t, 1);
1167 if (!var_info) return NULL;
1168 var_info->bandwidth = self->bandwidth;
1169 var_info->width = self->width;
1170 var_info->height = self->height;
1175 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1181 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1182 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1184 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1185 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1186 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1188 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1189 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1190 player->http_content_size = (bytes > 0) ? bytes : 0;
1193 /* handling audio clip which has vbr. means duration is keep changing */
1194 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1203 __mmplayer_eos_timer_cb(gpointer u_data)
1205 mmplayer_t *player = NULL;
1206 MMHandleType attrs = 0;
1209 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1211 player = (mmplayer_t *)u_data;
1212 attrs = MMPLAYER_GET_ATTRS(player);
1214 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1218 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1219 if (ret_value != MM_ERROR_NONE)
1220 LOGE("seeking to 0 failed in repeat play");
1223 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1226 /* we are returning FALSE as we need only one posting */
1231 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1233 MMPLAYER_RETURN_IF_FAIL(player);
1235 /* post now if delay is zero */
1236 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1237 LOGD("eos delay is zero. posting EOS now");
1238 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1240 if (player->audio_decoded_cb)
1241 _mmplayer_cancel_eos_timer(player);
1246 /* cancel if existing */
1247 _mmplayer_cancel_eos_timer(player);
1249 /* init new timeout */
1250 /* NOTE : consider give high priority to this timer */
1251 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1253 player->eos_timer = g_timeout_add(delay_in_ms,
1254 __mmplayer_eos_timer_cb, player);
1256 player->context.global_default = g_main_context_default();
1257 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1259 /* check timer is valid. if not, send EOS now */
1260 if (player->eos_timer == 0) {
1261 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1262 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1267 __mmplayer_gst_pending_seek(mmplayer_t *player)
1269 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1270 int ret = MM_ERROR_NONE;
1274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1276 if (!player->pending_seek.is_pending) {
1277 LOGD("pending seek is not reserved. nothing to do.");
1281 /* check player state if player could pending seek or not. */
1282 current_state = MMPLAYER_CURRENT_STATE(player);
1284 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1285 LOGW("try to pending seek in %s state, try next time. ",
1286 MMPLAYER_STATE_GET_NAME(current_state));
1290 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1292 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1293 if (ret != MM_ERROR_NONE)
1294 LOGE("failed to seek pending position. just keep staying current position.");
1296 player->pending_seek.is_pending = false;
1304 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1306 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1308 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1310 audiobin = player->pipeline->audiobin; /* can be null */
1311 videobin = player->pipeline->videobin; /* can be null */
1312 textbin = player->pipeline->textbin; /* can be null */
1314 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1316 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1317 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1319 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1320 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1322 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1323 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1329 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1331 mmplayer_gst_element_t *textbin;
1334 MMPLAYER_RETURN_IF_FAIL(player &&
1336 player->pipeline->textbin);
1338 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1340 textbin = player->pipeline->textbin;
1343 LOGD("Drop subtitle text after getting EOS");
1345 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1346 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1348 player->is_subtitle_force_drop = TRUE;
1350 if (player->is_subtitle_force_drop == TRUE) {
1351 LOGD("Enable subtitle data path without drop");
1353 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1354 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1356 LOGD("non-connected with external display");
1358 player->is_subtitle_force_drop = FALSE;
1364 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1366 MMHandleType attrs = 0;
1371 /* NOTE : EOS event is coming multiple time. watch out it */
1372 /* check state. we only process EOS when pipeline state goes to PLAYING */
1373 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1374 LOGD("EOS received on non-playing state. ignoring it");
1378 if (player->pipeline && player->pipeline->textbin)
1379 __mmplayer_drop_subtitle(player, TRUE);
1381 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1382 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1384 /* rewind if repeat count is greater then zero */
1385 /* get play count */
1386 attrs = MMPLAYER_GET_ATTRS(player);
1388 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1390 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1392 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1393 if (player->playback_rate < 0.0) {
1394 player->resumed_by_rewind = TRUE;
1395 _mmplayer_set_mute((MMHandleType)player, false);
1396 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1399 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1402 player->sent_bos = FALSE;
1404 LOGD("do not post eos msg for repeating");
1409 if (player->pipeline)
1410 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1412 /* post eos message to application */
1413 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1415 /* reset last position */
1416 player->last_position = 0;
1423 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1425 GError *error = NULL;
1426 gchar *debug = NULL;
1430 /* generating debug info before returning error */
1431 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1433 /* get error code */
1434 gst_message_parse_error(msg, &error, &debug);
1436 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1437 /* Note : the streaming error from the streaming source is handled
1438 * using __mmplayer_handle_streaming_error.
1440 __mmplayer_handle_streaming_error(player, msg, error);
1442 /* dump state of all element */
1443 _mmplayer_dump_pipeline_state(player);
1445 /* translate gst error code to msl error code. then post it
1446 * to application if needed
1448 __mmplayer_handle_gst_error(player, msg, error);
1451 LOGE("error debug : %s", debug);
1454 MMPLAYER_FREEIF(debug);
1455 g_error_free(error);
1462 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1464 MMMessageParamType msg_param = {0, };
1465 int bRet = MM_ERROR_NONE;
1468 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1470 if (!MMPLAYER_IS_STREAMING(player)) {
1471 LOGW("this is not streaming playback.");
1475 MMPLAYER_CMD_LOCK(player);
1477 if (!player->streamer) {
1478 LOGW("Pipeline is shutting down");
1479 MMPLAYER_CMD_UNLOCK(player);
1483 /* ignore the remained buffering message till getting 100% msg */
1484 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1485 gint buffer_percent = 0;
1487 gst_message_parse_buffering(msg, &buffer_percent);
1489 if (buffer_percent == MAX_BUFFER_PERCENT) {
1490 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1491 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1492 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1494 MMPLAYER_CMD_UNLOCK(player);
1498 /* ignore the remained buffering message */
1499 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1500 gint buffer_percent = 0;
1502 gst_message_parse_buffering(msg, &buffer_percent);
1504 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1505 player->streamer->buffering_percent, buffer_percent);
1507 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1508 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1509 player->streamer->buffering_req.is_pre_buffering = FALSE;
1511 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1513 LOGD("interrupted buffering - ignored the remained buffering msg!");
1514 MMPLAYER_CMD_UNLOCK(player);
1519 __mmplayer_update_buffer_setting(player, msg);
1521 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1523 if (bRet == MM_ERROR_NONE) {
1524 msg_param.connection.buffering = player->streamer->buffering_percent;
1525 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1527 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1528 player->pending_resume &&
1529 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1531 player->is_external_subtitle_added_now = FALSE;
1532 player->pending_resume = FALSE;
1533 _mmplayer_resume((MMHandleType)player);
1536 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1537 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1539 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1540 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1541 player->seek_state = MMPLAYER_SEEK_NONE;
1542 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1543 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1544 /* Considering the async state transition in case of RTSP.
1545 After getting state change gst msg, seek completed msg will be posted. */
1546 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1550 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1551 if (!player->streamer) {
1552 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1553 MMPLAYER_CMD_UNLOCK(player);
1557 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1559 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1560 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1562 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1563 msg_param.connection.buffering = player->streamer->buffering_percent;
1564 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1566 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1569 msg_param.connection.buffering = player->streamer->buffering_percent;
1570 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1573 MMPLAYER_CMD_UNLOCK(player);
1581 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1583 mmplayer_gst_element_t *mainbin;
1584 GstState oldstate = GST_STATE_NULL;
1585 GstState newstate = GST_STATE_NULL;
1586 GstState pending = GST_STATE_NULL;
1589 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1591 mainbin = player->pipeline->mainbin;
1593 /* we only handle messages from pipeline */
1594 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1597 gst_message_parse_state_changed(msg, &oldstate, &newstate, &pending);
1599 LOGD("state changed [%s] : %s ---> %s final : %s",
1600 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1601 gst_element_state_get_name((GstState)oldstate),
1602 gst_element_state_get_name((GstState)newstate),
1603 gst_element_state_get_name((GstState)pending));
1605 if (newstate == GST_STATE_PLAYING) {
1606 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1608 int retVal = MM_ERROR_NONE;
1609 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1611 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1613 if (MM_ERROR_NONE != retVal)
1614 LOGE("failed to seek pending position. just keep staying current position.");
1616 player->pending_seek.is_pending = false;
1620 if (oldstate == newstate) {
1621 LOGD("pipeline reports state transition to old state");
1626 case GST_STATE_PAUSED:
1628 gboolean prepare_async = FALSE;
1630 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1631 // managed prepare async case
1632 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1633 LOGD("checking prepare mode for async transition - %d", prepare_async);
1636 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1637 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1639 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1640 _mm_player_streaming_set_content_bitrate(player->streamer,
1641 player->total_maximum_bitrate, player->total_bitrate);
1643 if (player->pending_seek.is_pending) {
1644 LOGW("trying to do pending seek");
1645 MMPLAYER_CMD_LOCK(player);
1646 __mmplayer_gst_pending_seek(player);
1647 MMPLAYER_CMD_UNLOCK(player);
1653 case GST_STATE_PLAYING:
1655 if (MMPLAYER_IS_STREAMING(player)) {
1656 // managed prepare async case when buffering is completed
1657 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1658 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1659 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1660 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1662 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1664 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1665 if (player->streamer->buffering_percent < 100) {
1667 MMMessageParamType msg_param = {0, };
1668 LOGW("Posting Buffering Completed Message to Application !!!");
1670 msg_param.connection.buffering = 100;
1671 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1676 if (player->gapless.stream_changed) {
1677 _mmplayer_update_content_attrs(player, ATTR_ALL);
1678 player->gapless.stream_changed = FALSE;
1681 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1682 player->seek_state = MMPLAYER_SEEK_NONE;
1683 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1687 case GST_STATE_VOID_PENDING:
1688 case GST_STATE_NULL:
1689 case GST_STATE_READY:
1699 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1701 const gchar *structure_name;
1702 gint count = 0, idx = 0;
1705 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1707 if (gst_message_get_structure(msg) == NULL)
1710 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1711 if (!structure_name)
1714 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1716 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1717 const GValue *var_info = NULL;
1719 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1720 if (var_info != NULL) {
1721 if (player->adaptive_info.var_list)
1722 g_list_free_full(player->adaptive_info.var_list, g_free);
1724 /* share addr or copy the list */
1725 player->adaptive_info.var_list =
1726 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1728 count = g_list_length(player->adaptive_info.var_list);
1730 stream_variant_t *temp = NULL;
1732 /* print out for debug */
1733 LOGD("num of variant_info %d", count);
1734 for (idx = 0; idx < count; idx++) {
1735 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1737 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1743 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1744 gint num_buffers = 0;
1745 gint extra_num_buffers = 0;
1747 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1748 LOGD("video_num_buffers : %d", num_buffers);
1749 mm_player_set_attribute((MMHandleType)player, NULL,
1750 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1753 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1754 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1755 mm_player_set_attribute((MMHandleType)player, NULL,
1756 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1761 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1762 _mmplayer_track_update_text_attr_info(player, msg);
1764 /* custom message */
1765 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1766 MMMessageParamType msg_param = {0,};
1767 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1768 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1771 /* custom message for RTSP attribute :
1772 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1773 sdp which has contents info is received when rtsp connection is opened.
1774 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1775 if (!strcmp(structure_name, "rtspsrc_properties")) {
1776 g_autofree gchar *audio_codec = NULL;
1777 g_autofree gchar *video_codec = NULL;
1778 g_autofree gchar *video_frame_size = NULL;
1780 gst_structure_get(gst_message_get_structure(msg),
1781 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1782 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1783 player->streaming_type = _mmplayer_get_stream_service_type(player);
1785 gst_structure_get(gst_message_get_structure(msg),
1786 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1787 LOGD("rtsp_audio_codec : %s", audio_codec);
1789 mm_player_set_attribute((MMHandleType)player, NULL,
1790 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1792 gst_structure_get(gst_message_get_structure(msg),
1793 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1794 LOGD("rtsp_video_codec : %s", video_codec);
1796 mm_player_set_attribute((MMHandleType)player, NULL,
1797 "content_video_codec", video_codec, strlen(video_codec), NULL);
1799 gst_structure_get(gst_message_get_structure(msg),
1800 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1801 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1802 if (video_frame_size) {
1803 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1804 mm_player_set_attribute((MMHandleType)player, NULL,
1805 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1806 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1808 g_strfreev(res_str);
1817 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1819 mmplayer_gst_element_t *mainbin;
1822 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1824 mainbin = player->pipeline->mainbin;
1826 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1828 /* we only handle messages from pipeline */
1829 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1832 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1833 if (player->is_external_subtitle_present)
1834 _mmplayer_sync_subtitle_pipeline(player);
1836 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1837 player->seek_state = MMPLAYER_SEEK_NONE;
1838 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1839 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1840 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1841 LOGD("sync %s state(%s) with parent state(%s)",
1842 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1843 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1844 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1846 /* In case of streaming, pause is required before finishing seeking by buffering.
1847 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1848 Because the buffering state is controlled according to the state transition for force resume,
1849 the decodebin state should be paused as player state. */
1850 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1853 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1854 (player->streamer) &&
1855 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1856 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1857 GstQuery *query = NULL;
1858 gboolean busy = FALSE;
1861 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1862 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1863 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1864 gst_query_parse_buffering_percent(query, &busy, &percent);
1865 gst_query_unref(query);
1867 LOGD("buffered percent(%s): %d",
1868 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1872 __mmplayer_handle_buffering_playback(player);
1875 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1885 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1887 GValue val = { 0, };
1889 guint indent = GPOINTER_TO_UINT(user_data);
1891 if (!gst_tag_list_copy_value(&val, tags, tag))
1894 if (G_VALUE_HOLDS_STRING(&val))
1895 str = g_value_dup_string(&val);
1897 str = gst_value_serialize(&val);
1899 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1901 g_value_unset(&val);
1906 __mmplayer_dump_collection(GstStreamCollection * collection)
1910 GstTagList *tags = NULL;
1912 GstCaps *caps = NULL;
1914 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1915 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1916 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1917 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1918 gst_stream_get_stream_flags(stream));
1919 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1921 caps = gst_stream_get_caps(stream);
1923 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1924 gst_caps_unref(caps);
1928 tags = gst_stream_get_tags(stream);
1931 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1932 gst_tag_list_unref(tags);
1939 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1940 GstStream *stream, GParamSpec *pspec, gpointer data)
1942 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1943 gst_stream_get_stream_id(stream), pspec->name, collection);
1944 if (g_str_equal(pspec->name, "caps")) {
1945 GstCaps *caps = gst_stream_get_caps(stream);
1946 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1947 gst_caps_unref(caps);
1951 if (g_str_equal (pspec->name, "tags")) {
1952 GstTagList *tags = gst_stream_get_tags(stream);
1955 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1956 gst_tag_list_unref(tags);
1963 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1965 mmplayer_t *player = (mmplayer_t *)(data);
1967 MMPLAYER_RETURN_IF_FAIL(player);
1968 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1970 switch (GST_MESSAGE_TYPE(msg)) {
1971 case GST_MESSAGE_UNKNOWN:
1972 LOGD("unknown message received");
1975 case GST_MESSAGE_EOS:
1976 LOGD("GST_MESSAGE_EOS received");
1977 __mmplayer_gst_handle_eos_message(player, msg);
1980 case GST_MESSAGE_ERROR:
1981 _mmplayer_set_reconfigure_state(player, FALSE);
1982 __mmplayer_gst_handle_error_message(player, msg);
1985 case GST_MESSAGE_WARNING:
1988 GError *error = NULL;
1990 gst_message_parse_warning(msg, &error, &debug);
1992 LOGD("warning : %s", error->message);
1993 LOGD("debug : %s", debug);
1995 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1997 MMPLAYER_FREEIF(debug);
1998 g_error_free(error);
2002 case GST_MESSAGE_TAG:
2004 LOGD("GST_MESSAGE_TAG");
2005 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2006 LOGW("failed to extract tags from gstmessage");
2010 case GST_MESSAGE_BUFFERING:
2011 __mmplayer_gst_handle_buffering_message(player, msg);
2014 case GST_MESSAGE_STATE_CHANGED:
2015 __mmplayer_gst_handle_state_message(player, msg);
2018 case GST_MESSAGE_CLOCK_LOST:
2020 GstClock *clock = NULL;
2021 gboolean need_new_clock = FALSE;
2023 gst_message_parse_clock_lost(msg, &clock);
2024 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2026 if (!player->videodec_linked)
2027 need_new_clock = TRUE;
2028 else if (!player->ini.use_system_clock)
2029 need_new_clock = TRUE;
2031 if (need_new_clock) {
2032 LOGD("Provide clock is TRUE, do pause->resume");
2033 _mmplayer_gst_pause(player, FALSE);
2034 _mmplayer_gst_resume(player, FALSE);
2039 case GST_MESSAGE_NEW_CLOCK:
2041 GstClock *clock = NULL;
2042 gst_message_parse_new_clock(msg, &clock);
2043 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2047 case GST_MESSAGE_ELEMENT:
2048 __mmplayer_gst_handle_element_message(player, msg);
2051 case GST_MESSAGE_DURATION_CHANGED:
2053 LOGD("GST_MESSAGE_DURATION_CHANGED");
2054 if (!__mmplayer_gst_handle_duration(player, msg))
2055 LOGW("failed to update duration");
2059 case GST_MESSAGE_ASYNC_START:
2060 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2063 case GST_MESSAGE_ASYNC_DONE:
2064 __mmplayer_gst_handle_async_done_message(player, msg);
2066 case GST_MESSAGE_STREAM_COLLECTION:
2068 GstStreamCollection *collection = NULL;
2069 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2071 gst_message_parse_stream_collection(msg, &collection);
2073 __mmplayer_dump_collection(collection);
2074 if (player->collection && player->stream_notify_id) {
2075 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2076 player->stream_notify_id = 0;
2078 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2079 if (player->collection) {
2080 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2081 (GCallback)__mmplayer_stream_notify_cb, player);
2083 gst_object_unref(collection);
2086 case GST_MESSAGE_STREAMS_SELECTED:
2088 GstStreamCollection *collection = NULL;
2089 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2091 gst_message_parse_streams_selected(msg, &collection);
2093 guint len = gst_message_streams_selected_get_size(msg);
2094 for (guint i = 0; i < len; i++) {
2095 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2096 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2097 gst_stream_get_stream_type(stream));
2098 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2099 LOGD("not supported track type");
2100 gst_object_unref(stream);
2103 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2104 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2105 int stream_index = INVALID_TRACK_INDEX;
2106 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2107 player->track[type].active_track_index = stream_index;
2108 LOGD("selected this stream, update active idx : %d",
2109 player->track[type].active_track_index);
2112 gst_object_unref(stream);
2114 gst_object_unref(collection);
2119 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2120 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2121 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2122 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2123 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2124 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2125 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2126 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2127 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2128 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2129 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2130 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2131 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2132 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2133 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2140 /* should not call 'gst_message_unref(msg)' */
2144 static GstBusSyncReply
2145 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2147 mmplayer_t *player = (mmplayer_t *)data;
2148 GstBusSyncReply reply = GST_BUS_DROP;
2150 if (!(player->pipeline && player->pipeline->mainbin)) {
2151 LOGE("player pipeline handle is null");
2152 return GST_BUS_PASS;
2155 if (!__mmplayer_gst_check_useful_message(player, message)) {
2156 gst_message_unref(message);
2157 return GST_BUS_DROP;
2160 switch (GST_MESSAGE_TYPE(message)) {
2161 case GST_MESSAGE_TAG:
2162 __mmplayer_gst_extract_tag_from_msg(player, message);
2166 GstTagList *tags = NULL;
2168 gst_message_parse_tag(message, &tags);
2170 LOGE("TAGS received from element \"%s\".",
2171 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2173 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2174 gst_tag_list_unref(tags);
2182 case GST_MESSAGE_DURATION_CHANGED:
2183 __mmplayer_gst_handle_duration(player, message);
2185 case GST_MESSAGE_ELEMENT:
2187 const gchar *klass = NULL;
2188 klass = gst_element_factory_get_metadata
2189 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2190 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2191 reply = GST_BUS_PASS;
2194 __mmplayer_gst_handle_element_message(player, message);
2197 case GST_MESSAGE_ASYNC_DONE:
2198 /* NOTE:Don't call gst_callback directly
2199 * because previous frame can be showed even though this message is received for seek.
2202 reply = GST_BUS_PASS;
2206 if (reply == GST_BUS_DROP)
2207 gst_message_unref(message);
2213 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2215 GstElement *appsrc = element;
2216 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2217 GstBuffer *buffer = NULL;
2218 GstFlowReturn ret = GST_FLOW_OK;
2221 MMPLAYER_RETURN_IF_FAIL(element);
2222 MMPLAYER_RETURN_IF_FAIL(buf);
2224 buffer = gst_buffer_new();
2226 if (buf->offset < 0 || buf->len < 0) {
2227 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2231 if (buf->offset >= buf->len) {
2232 LOGD("call eos appsrc");
2233 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2237 if (buf->len - buf->offset < size)
2238 len = buf->len - buf->offset;
2240 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2241 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2242 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2245 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2247 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2253 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2255 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2257 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2259 buf->offset = (int)size;
2265 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2267 mmplayer_t *player = (mmplayer_t *)user_data;
2268 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2269 MMMessageParamType msg_param = {0,};
2270 guint64 current_level_bytes = 0;
2272 MMPLAYER_RETURN_IF_FAIL(player);
2274 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2275 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2276 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2277 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2279 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2283 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2285 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2287 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2288 msg_param.buffer_status.stream_type = stream_type;
2289 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2290 msg_param.buffer_status.bytes = current_level_bytes;
2292 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2296 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2298 mmplayer_t *player = (mmplayer_t *)user_data;
2299 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2300 MMMessageParamType msg_param = {0,};
2301 guint64 current_level_bytes = 0;
2303 MMPLAYER_RETURN_IF_FAIL(player);
2305 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2306 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2307 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2308 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2310 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2314 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2316 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2318 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2319 msg_param.buffer_status.stream_type = stream_type;
2320 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2321 msg_param.buffer_status.bytes = current_level_bytes;
2323 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2327 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2329 mmplayer_t *player = (mmplayer_t *)user_data;
2330 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2331 MMMessageParamType msg_param = {0,};
2333 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2335 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2336 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2337 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2338 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2340 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2344 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2346 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2347 msg_param.seek_data.stream_type = stream_type;
2348 msg_param.seek_data.offset = position;
2350 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2356 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2358 #define MAX_LEN_NAME 20
2360 gboolean ret = FALSE;
2361 GstPad *sinkpad = NULL;
2362 gchar *prefix = NULL;
2363 gchar dec_name[MAX_LEN_NAME] = {0, };
2364 main_element_id_e elem_id = MMPLAYER_M_NUM;
2366 mmplayer_gst_element_t *mainbin = NULL;
2367 GstElement *decodebin = NULL;
2368 GstCaps *dec_caps = NULL;
2372 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2374 player->pipeline->mainbin, FALSE);
2375 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2377 mainbin = player->pipeline->mainbin;
2379 case MM_PLAYER_STREAM_TYPE_AUDIO:
2381 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2383 case MM_PLAYER_STREAM_TYPE_VIDEO:
2385 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2388 LOGE("invalid type %d", type);
2392 if (mainbin[elem_id].gst) {
2393 LOGE("elem(%d) is already created", elem_id);
2397 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2399 /* create decodebin */
2400 decodebin = gst_element_factory_make("decodebin", dec_name);
2402 LOGE("failed to create %s", dec_name);
2406 /* raw pad handling signal */
2407 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2408 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2410 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2411 before looking for any elements that can handle that stream.*/
2412 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2413 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2415 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2416 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2417 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2419 /* This signal is emitted when a element is added to the bin.*/
2420 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2421 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2423 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2424 LOGE("failed to add new decodebin");
2428 dec_caps = gst_pad_query_caps(srcpad, NULL);
2431 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2433 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2434 gst_caps_unref(dec_caps);
2437 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2439 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2440 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2443 gst_object_unref(GST_OBJECT(sinkpad));
2445 gst_element_sync_state_with_parent(decodebin);
2447 mainbin[elem_id].id = elem_id;
2448 mainbin[elem_id].gst = decodebin;
2455 gst_object_unref(GST_OBJECT(sinkpad));
2458 gst_element_set_state(decodebin, GST_STATE_NULL);
2459 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2460 gst_object_unref(decodebin);
2468 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2470 #define MAX_LEN_NAME 20
2471 mmplayer_gst_element_t *mainbin = NULL;
2472 gchar *prefix = NULL;
2473 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2475 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2476 GstElement *src = NULL, *queue = NULL;
2477 GstPad *srcpad = NULL;
2480 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2481 player->pipeline->mainbin, FALSE);
2483 mainbin = player->pipeline->mainbin;
2485 LOGD("type(%d) path is creating", type);
2487 case MM_PLAYER_STREAM_TYPE_AUDIO:
2489 if (mainbin[MMPLAYER_M_SRC].gst)
2490 src_id = MMPLAYER_M_2ND_SRC;
2492 src_id = MMPLAYER_M_SRC;
2493 queue_id = MMPLAYER_M_A_BUFFER;
2495 case MM_PLAYER_STREAM_TYPE_VIDEO:
2497 src_id = MMPLAYER_M_SRC;
2498 queue_id = MMPLAYER_M_V_BUFFER;
2500 case MM_PLAYER_STREAM_TYPE_TEXT:
2501 prefix = "subtitle";
2502 src_id = MMPLAYER_M_SUBSRC;
2503 queue_id = MMPLAYER_M_S_BUFFER;
2506 LOGE("invalid type %d", type);
2510 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2511 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2514 src = gst_element_factory_make("appsrc", src_name);
2516 LOGF("failed to create %s", src_name);
2520 mainbin[src_id].id = src_id;
2521 mainbin[src_id].gst = src;
2523 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2524 "caps", caps, NULL);
2526 /* size of many video frames are larger than default blocksize as 4096 */
2527 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2528 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2530 if (player->media_stream_buffer_max_size[type] > 0)
2531 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2533 if (player->media_stream_buffer_min_percent[type] > 0)
2534 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2536 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2537 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2539 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2540 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2541 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2542 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2543 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2544 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2547 queue = gst_element_factory_make("queue2", queue_name);
2549 LOGE("failed to create %s", queue_name);
2552 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2554 mainbin[queue_id].id = queue_id;
2555 mainbin[queue_id].gst = queue;
2557 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2558 LOGE("failed to add src");
2562 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2563 LOGE("failed to add queue");
2567 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2568 LOGE("failed to link src and queue");
2572 /* create decoder */
2573 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2575 LOGE("failed to get srcpad of queue");
2579 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2580 _mmplayer_gst_create_decoder(player, srcpad, caps);
2582 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2583 LOGE("failed to create decoder");
2584 gst_object_unref(GST_OBJECT(srcpad));
2588 gst_object_unref(GST_OBJECT(srcpad));
2592 if (mainbin[src_id].gst) {
2593 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2594 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2595 gst_object_unref(mainbin[src_id].gst);
2596 mainbin[src_id].gst = NULL;
2599 if (mainbin[queue_id].gst) {
2600 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2601 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2602 gst_object_unref(mainbin[queue_id].gst);
2603 mainbin[queue_id].gst = NULL;
2610 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2612 GstPad *sinkpad = NULL;
2613 GstCaps *caps = NULL;
2614 GstElement *new_element = NULL;
2615 GstStructure *str = NULL;
2616 const gchar *name = NULL;
2618 mmplayer_t *player = (mmplayer_t *)data;
2622 MMPLAYER_RETURN_IF_FAIL(element && pad);
2623 MMPLAYER_RETURN_IF_FAIL(player &&
2625 player->pipeline->mainbin);
2627 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2628 * num_dynamic_pad will decreased after creating a sinkbin.
2630 player->num_dynamic_pad++;
2631 LOGD("stream count inc : %d", player->num_dynamic_pad);
2633 caps = gst_pad_query_caps(pad, NULL);
2634 MMPLAYER_CHECK_NULL(caps);
2636 str = gst_caps_get_structure(caps, 0);
2637 name = gst_structure_get_string(str, "media");
2639 LOGE("cannot get mimetype from structure.");
2643 if (strstr(name, "video")) {
2645 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2647 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2648 if (player->v_stream_caps) {
2649 gst_caps_unref(player->v_stream_caps);
2650 player->v_stream_caps = NULL;
2653 new_element = gst_element_factory_make("fakesink", NULL);
2654 player->num_dynamic_pad--;
2659 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2660 LOGE("failed to autoplug for caps");
2664 gst_caps_unref(caps);
2669 /* execute new_element if created*/
2671 LOGD("adding new element to pipeline");
2673 /* set state to READY before add to bin */
2674 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2676 /* add new element to the pipeline */
2677 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2678 LOGE("failed to add autoplug element to bin");
2682 /* get pad from element */
2683 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2685 LOGE("failed to get sinkpad from autoplug element");
2690 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2691 LOGE("failed to link autoplug element");
2695 gst_object_unref(sinkpad);
2698 /* run. setting PLAYING here since streaming source is live source */
2699 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2703 gst_caps_unref(caps);
2709 STATE_CHANGE_FAILED:
2711 /* FIXIT : take care if new_element has already added to pipeline */
2713 gst_object_unref(GST_OBJECT(new_element));
2716 gst_object_unref(GST_OBJECT(sinkpad));
2719 gst_caps_unref(caps);
2721 /* FIXIT : how to inform this error to MSL ????? */
2722 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2723 * then post an error to application
2728 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2730 mmplayer_t *player = (mmplayer_t *)data;
2734 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2735 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2736 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2737 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2739 * [1] audio and video will be dumped with filesink.
2740 * [2] autoplugging is done by just using pad caps.
2741 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2742 * and the video will be dumped via filesink.
2744 if (player->num_dynamic_pad == 0) {
2745 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2747 if (!_mmplayer_gst_remove_fakesink(player,
2748 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2749 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2750 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2751 * source element are not same. To overcome this situation, this function will called
2752 * several places and several times. Therefore, this is not an error case.
2757 /* create dot before error-return. for debugging */
2758 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2760 player->no_more_pad = TRUE;
2766 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2768 GstElement *element = NULL;
2769 gchar *user_agent = NULL;
2770 MMHandleType attrs = 0;
2773 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2775 /* get profile attribute */
2776 attrs = MMPLAYER_GET_ATTRS(player);
2778 LOGE("failed to get content attribute");
2782 element = gst_element_factory_make("rtspsrc", "rtsp source");
2784 LOGE("failed to create rtspsrc element");
2789 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2791 SECURE_LOGD("user_agent : %s", user_agent);
2793 /* setting property to streaming source */
2794 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2796 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2798 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2799 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2800 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2801 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2807 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2809 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2811 mmplayer_t *player = (mmplayer_t *)data;
2812 MMHandleType attrs = 0;
2813 gchar *user_agent, *cookies, **cookie_list;
2814 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2815 user_agent = cookies = NULL;
2819 MMPLAYER_RETURN_IF_FAIL(player);
2821 LOGD("source element %s", GST_ELEMENT_NAME(source));
2823 attrs = MMPLAYER_GET_ATTRS(player);
2825 LOGE("failed to get content attribute");
2829 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2830 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2832 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2833 http_timeout = player->ini.http_timeout;
2835 SECURE_LOGD("cookies : %s", cookies);
2836 SECURE_LOGD("user_agent : %s", user_agent);
2837 LOGD("timeout : %d", http_timeout);
2839 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2841 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2842 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2843 g_strfreev(cookie_list);
2847 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2853 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2855 mmplayer_t *player = (mmplayer_t *)data;
2856 gchar *user_agent = NULL;
2857 MMHandleType attrs = 0;
2860 MMPLAYER_RETURN_IF_FAIL(player);
2862 attrs = MMPLAYER_GET_ATTRS(player);
2864 LOGE("failed to get content attribute");
2868 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2870 SECURE_LOGD("user_agent : %s", user_agent);
2873 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2879 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2881 mmplayer_t *player = (mmplayer_t *)data;
2882 GstElement *source = NULL;
2885 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2887 g_object_get(orig, pspec->name, &source, NULL);
2889 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2890 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2892 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2893 __mmplayer_http_src_setup(source, data);
2894 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2895 __mmplayer_rtsp_src_setup(source, data);
2896 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2897 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2898 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2899 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2900 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2902 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2903 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2904 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2905 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2907 gst_object_unref (source);
2913 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2914 GstStream * stream, gpointer data)
2916 #define RET_SELECT 1
2918 #define RET_DEPENDS_ON_DECODEBIN -1
2920 GstStreamType stype = gst_stream_get_stream_type(stream);
2921 mmplayer_t *player = (mmplayer_t *)data;
2922 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2923 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2924 g_autofree gchar *caps_str = NULL;
2925 GstStructure *caps_structure = NULL;
2926 int stream_index = INVALID_TRACK_INDEX;
2927 int ret = MM_ERROR_NONE;
2929 LOGD("Stream type %s flags 0x%x",
2930 gst_stream_type_get_name(stype),
2931 gst_stream_get_stream_flags(stream));
2932 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2934 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
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);
2952 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2953 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2954 LOGD("No caps info, depends on decodebin");
2955 _mmplayer_track_update_stream(player, type, stream);
2956 return RET_DEPENDS_ON_DECODEBIN;
2959 LOGD("No caps info, skip it");
2964 case GST_STREAM_TYPE_AUDIO:
2966 if (caps_structure) {
2967 gint samplerate = 0;
2970 gst_structure_get_int(caps_structure, "rate", &samplerate);
2971 gst_structure_get_int(caps_structure, "channels", &channels);
2972 if (samplerate == 0 && channels > 0) {
2973 LOGW("Skip corrupted audio stream");
2977 if (g_strrstr(caps_str, "mobile-xmf"))
2978 mm_player_set_attribute((MMHandleType)player, NULL,
2979 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2983 case GST_STREAM_TYPE_VIDEO:
2985 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2986 LOGD("do not support muti track video");
2990 // FIXME: it cause block during preparing
2991 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2994 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2995 /* don't make video because of not required */
2996 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2997 (!player->set_mode.video_export)) {
2998 LOGD("no need video decoding, skip video stream");
3003 if (caps_structure) {
3006 gst_structure_get_int(caps_structure, "width", &width);
3008 if (player->v_stream_caps) {
3009 gst_caps_unref(player->v_stream_caps);
3010 player->v_stream_caps = NULL;
3013 player->v_stream_caps = gst_caps_copy(caps);
3014 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3019 case GST_STREAM_TYPE_TEXT:
3022 LOGW("Skip not supported stream type");
3026 _mmplayer_track_update_stream(player, type, stream);
3028 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3030 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3031 (ret == MM_ERROR_NONE)) {
3032 player->track[type].active_track_index = stream_index;
3033 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3034 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3035 _mmplayer_set_audio_attrs(player, caps);
3039 if (player->track[type].active_track_index == stream_index) {
3040 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3044 LOGD("Skip stream");
3049 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3050 GstStream * stream, gpointer data)
3052 mmplayer_t *player = (mmplayer_t *)data;
3053 GstStreamType stype = gst_stream_get_stream_type(stream);
3056 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3058 LOGD("stream type %s", gst_stream_type_get_name(stype));
3060 /* public does not support audio hw decoder at the moment */
3062 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3063 LOGW("video decoder resource is already acquired, skip it.");
3067 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3068 LOGE("failed to acquire video decoder resource");
3071 player->interrupted_by_resource = FALSE;
3077 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3079 GstIterator *iter = NULL;
3080 GValue item = {0, };
3081 GstElement *ch_element = NULL;
3082 GstElementFactory *ch_factory = NULL;
3085 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3087 iter = gst_bin_iterate_recurse(bin);
3088 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3090 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3091 ch_element = g_value_get_object(&item);
3092 ch_factory = gst_element_get_factory(ch_element);
3093 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3094 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3095 LOGD("Find %s element", element_name);
3099 g_value_reset(&item);
3101 g_value_unset(&item);
3102 gst_iterator_free(iter);
3108 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3110 mmplayer_t *player = (mmplayer_t *)data;
3112 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3114 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3115 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3116 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3118 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3119 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3120 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3123 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3125 mmplayer_t *player = (mmplayer_t *)data;
3126 int video_codec_type = 0;
3127 int audio_codec_type = 0;
3129 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3131 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3132 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3134 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3136 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3137 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3138 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3139 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3141 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3142 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3146 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3148 gchar *factory_name = NULL;
3149 mmplayer_t *player = (mmplayer_t *)data;
3152 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3154 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3156 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3158 if (g_strrstr(factory_name, "urisourcebin")) {
3159 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3161 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3163 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3165 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3167 LOGW("failed to find decodebin3");
3169 } else if (g_strrstr(factory_name, "parsebin")) {
3170 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3171 __mmplayer_parsebin_setup(GST_BIN(element), data);
3173 _mmplayer_gst_element_added(child, element, data);
3178 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3182 MMPLAYER_RETURN_IF_FAIL(player);
3183 MMPLAYER_RETURN_IF_FAIL(removed_element);
3185 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3187 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3188 GList *node = player->signals[type];
3190 GList *next_node = node->next;
3191 mmplayer_signal_item_t *item = node->data;
3192 if (item && item->obj == G_OBJECT(removed_element)) {
3193 player->signals[type] = g_list_delete_link(player->signals[type], node);
3194 MMPLAYER_FREEIF(item);
3204 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3206 mmplayer_t *player = (mmplayer_t *)data;
3210 MMPLAYER_RETURN_IF_FAIL(player);
3212 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3214 __mmplayer_delete_signal_connection(player, element);
3220 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3222 GstElement *uridecodebin3 = NULL;
3225 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3227 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3228 if (!uridecodebin3) {
3229 LOGE("failed to create uridecodebin3");
3234 SECURE_LOGD("uri : %s", player->profile.uri);
3236 /* setting property to streaming source */
3237 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3238 "message-forward", TRUE,
3239 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3240 "use-buffering", TRUE, NULL);
3242 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3245 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3248 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3251 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3252 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3254 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3255 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3257 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3258 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3260 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3261 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3263 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3264 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3266 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3267 LOGW("[DASH] this is still experimental feature");
3270 return uridecodebin3;
3274 __mmplayer_gst_make_http_src(mmplayer_t *player)
3276 #define MAX_RETRY_COUNT 10
3277 GstElement *element = NULL;
3278 MMHandleType attrs = 0;
3279 gchar *user_agent, *cookies, **cookie_list;
3280 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3282 user_agent = cookies = NULL;
3286 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3288 /* get profile attribute */
3289 attrs = MMPLAYER_GET_ATTRS(player);
3291 LOGE("failed to get content attribute");
3295 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3297 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3299 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3304 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3305 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3307 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3308 http_timeout = player->ini.http_timeout;
3311 SECURE_LOGD("location : %s", player->profile.uri);
3312 SECURE_LOGD("cookies : %s", cookies);
3313 SECURE_LOGD("user_agent : %s", user_agent);
3314 LOGD("timeout : %d", http_timeout);
3316 /* setting property to streaming source */
3317 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3318 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3319 "retries", MAX_RETRY_COUNT, NULL);
3321 /* parsing cookies */
3322 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3323 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3324 g_strfreev(cookie_list);
3328 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3330 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3331 LOGW("[DASH] this is still experimental feature");
3338 __mmplayer_gst_make_file_src(mmplayer_t *player)
3340 GstElement *element = NULL;
3343 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3345 LOGD("using filesrc for 'file://' handler");
3346 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3347 LOGE("failed to get storage info");
3351 element = gst_element_factory_make("filesrc", "source");
3353 LOGE("failed to create filesrc");
3357 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3364 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3366 mmplayer_t *player = (mmplayer_t *)data;
3368 g_return_val_if_fail(player, FALSE);
3369 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3370 gst_message_ref(msg);
3372 g_mutex_lock(&player->bus_msg_q_lock);
3373 g_queue_push_tail(player->bus_msg_q, msg);
3374 g_mutex_unlock(&player->bus_msg_q_lock);
3376 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3377 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3378 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3382 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3384 mmplayer_t *player = (mmplayer_t *)(data);
3385 GstMessage *msg = NULL;
3388 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3390 player->pipeline->mainbin &&
3391 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3394 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3396 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3397 while (!player->bus_msg_thread_exit) {
3398 g_mutex_lock(&player->bus_msg_q_lock);
3399 msg = g_queue_pop_head(player->bus_msg_q);
3400 g_mutex_unlock(&player->bus_msg_q_lock);
3402 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3405 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3406 /* handle the gst msg */
3407 __mmplayer_gst_bus_msg_callback(msg, player);
3408 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3409 gst_message_unref(msg);
3412 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3419 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3421 gint64 dur_nsec = 0;
3422 gint64 pos_nsec = 0;
3425 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3427 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3428 return MM_ERROR_NONE;
3430 /* NOTE : duration cannot be zero except live streaming.
3431 * Since some element could have some timing problem with querying duration, try again.
3433 if (player->duration == 0) {
3434 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3435 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3436 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3437 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3438 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3439 player->pending_seek.is_pending = true;
3440 player->pending_seek.pos = position;
3441 player->seek_state = MMPLAYER_SEEK_NONE;
3442 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3443 return MM_ERROR_PLAYER_NO_OP;
3445 player->seek_state = MMPLAYER_SEEK_NONE;
3446 return MM_ERROR_PLAYER_SEEK;
3449 player->duration = dur_nsec;
3452 if (player->duration > 0 && player->duration < position) {
3453 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3454 return MM_ERROR_INVALID_ARGUMENT;
3457 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3458 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3459 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3460 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3461 player->seek_state = MMPLAYER_SEEK_NONE;
3462 return MM_ERROR_PLAYER_NO_OP;
3467 return MM_ERROR_NONE;
3471 __mmplayer_gst_check_seekable(mmplayer_t *player)
3473 GstQuery *query = NULL;
3474 gboolean seekable = FALSE;
3476 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3480 query = gst_query_new_seeking(GST_FORMAT_TIME);
3481 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3482 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3483 gst_query_unref(query);
3486 LOGW("non-seekable content");
3487 player->seek_state = MMPLAYER_SEEK_NONE;
3491 LOGW("failed to get seeking query");
3492 gst_query_unref(query); /* keep seeking operation */
3499 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3501 GstState element_state = GST_STATE_VOID_PENDING;
3502 GstState element_pending_state = GST_STATE_VOID_PENDING;
3503 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3507 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3508 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3510 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3513 ret = gst_element_set_state(element, state);
3514 if (ret == GST_STATE_CHANGE_FAILURE) {
3515 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3517 /* dump state of all element */
3518 _mmplayer_dump_pipeline_state(player);
3520 return MM_ERROR_PLAYER_INTERNAL;
3523 /* return here so state transition to be done in async mode */
3525 LOGD("async state transition. not waiting for state complete.");
3526 return MM_ERROR_NONE;
3529 /* wait for state transition */
3530 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3531 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3532 LOGE("failed to change [%s] element state to [%s] within %d sec",
3533 GST_ELEMENT_NAME(element),
3534 gst_element_state_get_name(state), timeout);
3536 LOGE(" [%s] state : %s pending : %s",
3537 GST_ELEMENT_NAME(element),
3538 gst_element_state_get_name(element_state),
3539 gst_element_state_get_name(element_pending_state));
3541 /* dump state of all element */
3542 _mmplayer_dump_pipeline_state(player);
3544 return MM_ERROR_PLAYER_INTERNAL;
3547 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3551 return MM_ERROR_NONE;
3555 _mmplayer_gst_start(mmplayer_t *player)
3557 int ret = MM_ERROR_NONE;
3558 gboolean async = FALSE;
3562 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3564 /* NOTE : if SetPosition was called before Start. do it now
3565 * streaming doesn't support it. so it should be always sync
3566 * !!create one more api to check if there is pending seek rather than checking variables
3568 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3569 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3570 ret = _mmplayer_gst_pause(player, FALSE);
3571 if (ret != MM_ERROR_NONE) {
3572 LOGE("failed to set state to PAUSED for pending seek");
3576 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3577 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3578 LOGW("failed to seek pending position. starting from the begin of content");
3581 LOGD("current state before doing transition");
3582 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3583 MMPLAYER_PRINT_STATE(player);
3585 /* set pipeline state to PLAYING */
3586 ret = _mmplayer_gst_set_state(player,
3587 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3588 if (ret != MM_ERROR_NONE) {
3589 LOGE("failed to set state to PLAYING");
3593 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3595 /* generating debug info before returning error */
3596 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3604 _mmplayer_gst_stop(mmplayer_t *player)
3606 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3607 MMHandleType attrs = 0;
3608 gboolean rewind = FALSE;
3610 int ret = MM_ERROR_NONE;
3614 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3615 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3617 LOGD("current state before doing transition");
3618 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3619 MMPLAYER_PRINT_STATE(player);
3621 attrs = MMPLAYER_GET_ATTRS(player);
3623 LOGE("cannot get content attribute");
3624 return MM_ERROR_PLAYER_INTERNAL;
3627 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3628 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3630 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3631 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3634 if (player->es_player_push_mode)
3635 /* disable the async state transition because there could be no data in the pipeline */
3636 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3639 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3641 if (player->es_player_push_mode) {
3642 /* enable the async state transition as default operation */
3643 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3646 /* return if set_state has failed */
3647 if (ret != MM_ERROR_NONE) {
3648 LOGE("failed to set state.");
3654 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3655 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3656 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3657 LOGW("failed to rewind");
3658 ret = MM_ERROR_PLAYER_SEEK;
3663 player->sent_bos = FALSE;
3665 if (player->es_player_push_mode) //for cloudgame
3668 /* wait for seek to complete */
3669 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3670 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3671 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3673 LOGE("fail to stop player.");
3674 ret = MM_ERROR_PLAYER_INTERNAL;
3675 _mmplayer_dump_pipeline_state(player);
3678 /* generate dot file if enabled */
3679 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3687 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3689 int ret = MM_ERROR_NONE;
3693 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3694 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3696 LOGD("current state before doing transition");
3697 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3698 MMPLAYER_PRINT_STATE(player);
3700 /* set pipeline status to PAUSED */
3701 ret = _mmplayer_gst_set_state(player,
3702 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3707 if (ret != MM_ERROR_NONE) {
3708 GstMessage *msg = NULL;
3709 GTimer *timer = NULL;
3710 gdouble MAX_TIMEOUT_SEC = 3;
3712 LOGE("failed to set state to PAUSED");
3714 if (!player->bus_watcher) {
3715 LOGE("there is no bus msg thread. pipeline is shutting down.");
3719 if (player->msg_posted) {
3720 LOGE("error msg is already posted.");
3724 timer = g_timer_new();
3725 g_timer_start(timer);
3727 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3730 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3732 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3733 GError *error = NULL;
3735 /* parse error code */
3736 gst_message_parse_error(msg, &error, NULL);
3738 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3739 /* Note : the streaming error from the streaming source is handled
3740 * using __mmplayer_handle_streaming_error.
3742 __mmplayer_handle_streaming_error(player, msg, error);
3745 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3747 if (error->domain == GST_STREAM_ERROR)
3748 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3749 else if (error->domain == GST_RESOURCE_ERROR)
3750 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3751 else if (error->domain == GST_LIBRARY_ERROR)
3752 ret = __mmplayer_gst_handle_library_error(player, error->code);
3753 else if (error->domain == GST_CORE_ERROR)
3754 ret = __mmplayer_gst_handle_core_error(player, error->code);
3756 g_error_free(error);
3758 player->msg_posted = TRUE;
3760 gst_message_unref(msg);
3762 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3764 gst_object_unref(bus);
3765 g_timer_stop(timer);
3766 g_timer_destroy(timer);
3771 if (MMPLAYER_USE_DECODEBIN(player)) {
3772 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3773 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3774 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3777 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3780 /* generate dot file before returning error */
3781 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3789 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3791 int ret = MM_ERROR_NONE;
3796 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3797 MM_ERROR_PLAYER_NOT_INITIALIZED);
3799 LOGD("current state before doing transition");
3800 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3801 MMPLAYER_PRINT_STATE(player);
3804 LOGD("do async state transition to PLAYING");
3806 /* set pipeline state to PLAYING */
3807 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3809 ret = _mmplayer_gst_set_state(player,
3810 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3811 if (ret != MM_ERROR_NONE) {
3812 LOGE("failed to set state to PLAYING");
3817 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3820 /* generate dot file */
3821 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3828 /* sending event to one of sinkelements */
3830 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3832 GstEvent *event2 = NULL;
3833 GList *sinks = NULL;
3834 gboolean res = FALSE;
3837 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3838 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3840 /* While adding subtitles in live feeds seek is getting called.
3841 Adding defensive check in framework layer.*/
3842 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3843 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3844 LOGE("Should not send seek event during live playback");
3849 if (player->play_subtitle)
3850 event2 = gst_event_copy((const GstEvent *)event);
3852 sinks = player->sink_elements;
3854 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3856 if (GST_IS_ELEMENT(sink)) {
3857 /* keep ref to the event */
3858 gst_event_ref(event);
3860 if ((res = gst_element_send_event(sink, event))) {
3861 LOGD("sending event[%s] to sink element [%s] success!",
3862 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3864 /* rtsp case, async_done is not called after seek during pause state */
3865 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3866 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3867 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3868 LOGD("RTSP seek completed, after pause state..");
3869 player->seek_state = MMPLAYER_SEEK_NONE;
3870 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3876 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3877 sinks = g_list_next(sinks);
3884 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3885 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3888 sinks = g_list_next(sinks);
3891 /* Note : Textbin is not linked to the video or audio bin.
3892 * It needs to send the event to the text sink separately.
3894 if (player->play_subtitle && player->pipeline) {
3895 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3897 if (GST_IS_ELEMENT(text_sink)) {
3898 /* keep ref to the event */
3899 gst_event_ref(event2);
3901 if ((res = gst_element_send_event(text_sink, event2)))
3902 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3903 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3905 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3906 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3908 gst_event_unref(event2);
3912 gst_event_unref(event);
3920 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3921 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3922 gint64 cur, GstSeekType stop_type, gint64 stop)
3924 GstEvent *event = NULL;
3925 gboolean result = FALSE;
3929 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3931 if (player->pipeline && player->pipeline->textbin)
3932 __mmplayer_drop_subtitle(player, FALSE);
3934 event = gst_event_new_seek(rate, format, flags, cur_type,
3935 cur, stop_type, stop);
3937 result = _mmplayer_gst_send_event_to_sink(player, event);
3945 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3947 int ret = MM_ERROR_NONE;
3948 gint64 pos_nsec = 0;
3949 gboolean accurate = FALSE;
3950 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3953 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3954 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3956 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3957 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3960 ret = __mmplayer_gst_check_position(player, position);
3961 if (ret != MM_ERROR_NONE) {
3962 LOGW("result of check position info 0x%X", ret);
3963 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3966 if (!__mmplayer_gst_check_seekable(player))
3967 return MM_ERROR_PLAYER_NO_OP;
3969 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3970 position, player->playback_rate, player->duration);
3972 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3973 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3974 This causes problem is position calculation during normal pause resume scenarios also.
3975 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3976 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3977 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3978 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3979 LOGW("getting current position failed in seek");
3981 player->last_position = pos_nsec;
3982 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3985 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3986 LOGD("not completed seek");
3987 return MM_ERROR_PLAYER_DOING_SEEK;
3990 if (!internal_called)
3991 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3993 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3994 that's why set position through property. */
3995 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3996 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3997 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3998 (!player->videodec_linked) && (!player->audiodec_linked)) {
4000 LOGD("[%s] set position =%"GST_TIME_FORMAT,
4001 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
4003 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
4004 player->seek_state = MMPLAYER_SEEK_NONE;
4005 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4007 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4009 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4011 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4013 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4014 GST_FORMAT_TIME, seek_flags,
4015 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4016 LOGE("failed to set position");
4021 /* NOTE : store last seeking point to overcome some bad operation
4022 * (returning zero when getting current position) of some elements
4024 player->last_position = position;
4026 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4027 if (player->playback_rate > 1.0)
4028 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4030 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4031 LOGD("buffering should be reset after seeking");
4032 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4033 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4037 return MM_ERROR_NONE;
4040 player->pending_seek.is_pending = true;
4041 player->pending_seek.pos = position;
4043 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4044 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4045 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4046 player->pending_seek.pos);
4048 return MM_ERROR_NONE;
4051 player->seek_state = MMPLAYER_SEEK_NONE;
4052 return MM_ERROR_PLAYER_SEEK;
4056 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4058 #define TRICKPLAY_OFFSET GST_MSECOND
4060 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4061 gint64 pos_nsec = 0;
4062 gboolean ret = TRUE;
4064 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4065 MM_ERROR_PLAYER_NOT_INITIALIZED);
4067 current_state = MMPLAYER_CURRENT_STATE(player);
4069 /* NOTE : query position except paused state to overcome some bad operation
4070 * please refer to below comments in details
4072 if (current_state != MM_PLAYER_STATE_PAUSED)
4073 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4075 /* NOTE : get last point to overcome some bad operation of some elements
4076 *(returning zero when getting current position in paused state
4077 * and when failed to get position during seeking
4079 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4080 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4082 if (player->playback_rate < 0.0)
4083 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4085 pos_nsec = player->last_position;
4088 pos_nsec = player->last_position;
4090 player->last_position = pos_nsec;
4092 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4095 if (player->duration > 0 && pos_nsec > player->duration)
4096 pos_nsec = player->duration;
4098 player->last_position = pos_nsec;
4101 *position = pos_nsec;
4103 return MM_ERROR_NONE;
4107 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4109 #define STREAMING_IS_FINISHED 0
4110 #define BUFFERING_MAX_PER 100
4111 #define DEFAULT_PER_VALUE -1
4112 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4114 mmplayer_gst_element_t *mainbin = NULL;
4115 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4116 gint64 buffered_total = 0;
4117 gint64 position = 0;
4118 gint buffered_sec = -1;
4119 GstBufferingMode mode = GST_BUFFERING_STREAM;
4120 gint64 content_size_time = player->duration;
4121 guint64 content_size_bytes = player->http_content_size;
4123 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4125 player->pipeline->mainbin,
4126 MM_ERROR_PLAYER_NOT_INITIALIZED);
4128 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4133 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4134 /* and rtsp is not ready yet. */
4135 LOGW("it's only used for http streaming case");
4136 return MM_ERROR_PLAYER_NO_OP;
4139 if (content_size_time <= 0 || content_size_bytes <= 0) {
4140 LOGW("there is no content size");
4141 return MM_ERROR_NONE;
4144 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4145 LOGW("fail to get current position");
4146 return MM_ERROR_NONE;
4149 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4150 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4152 mainbin = player->pipeline->mainbin;
4153 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4155 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4156 GstQuery *query = NULL;
4157 gint byte_in_rate = 0, byte_out_rate = 0;
4158 gint64 estimated_total = 0;
4160 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4161 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4162 LOGW("fail to get buffering query from queue2");
4164 gst_query_unref(query);
4165 return MM_ERROR_NONE;
4168 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4169 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4171 if (mode == GST_BUFFERING_STREAM) {
4172 /* using only queue in case of push mode(ts / mp3) */
4173 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4174 GST_FORMAT_BYTES, &buffered_total)) {
4175 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4176 end_per = 100 * buffered_total / content_size_bytes;
4179 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4181 guint num_of_ranges = 0;
4182 gint64 start_byte = 0, stop_byte = 0;
4184 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4185 if (estimated_total != STREAMING_IS_FINISHED) {
4186 /* buffered size info from queue2 */
4187 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4188 for (idx = 0; idx < num_of_ranges; idx++) {
4189 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4190 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4192 buffered_total += (stop_byte - start_byte);
4195 end_per = BUFFERING_MAX_PER;
4198 gst_query_unref(query);
4201 if (end_per == DEFAULT_PER_VALUE) {
4202 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4204 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4206 /* buffered size info from multiqueue */
4207 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4208 guint curr_size_bytes = 0;
4209 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4210 "curr-size-bytes", &curr_size_bytes, NULL);
4211 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4212 buffered_total += (gint64)curr_size_bytes;
4215 if (avg_byterate > 0)
4216 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4217 else if (player->total_maximum_bitrate > 0)
4218 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4219 else if (player->total_bitrate > 0)
4220 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4222 if (buffered_sec >= 0)
4223 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4227 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4228 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4230 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4231 buffered_total, buffered_sec, *start_pos, *end_pos);
4233 return MM_ERROR_NONE;
4237 _mmplayer_gst_create_source(mmplayer_t *player)
4239 GstElement *element = NULL;
4242 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4243 player->pipeline->mainbin, NULL);
4245 /* setup source for gapless play */
4246 switch (player->profile.uri_type) {
4248 case MM_PLAYER_URI_TYPE_FILE:
4249 element = __mmplayer_gst_make_file_src(player);
4251 case MM_PLAYER_URI_TYPE_URL_HTTP:
4252 element = __mmplayer_gst_make_http_src(player);
4255 LOGE("not support uri type %d", player->profile.uri_type);
4260 LOGE("failed to create source element");
4269 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4273 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4275 SECURE_LOGD("uri : %s", player->profile.uri);
4277 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4279 if ((player->v_stream_caps) &&
4280 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4281 return MM_ERROR_PLAYER_INTERNAL;
4283 if ((player->a_stream_caps) &&
4284 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4285 return MM_ERROR_PLAYER_INTERNAL;
4287 if ((player->s_stream_caps) &&
4288 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4289 return MM_ERROR_PLAYER_INTERNAL;
4292 return MM_ERROR_NONE;
4296 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4298 mmplayer_gst_element_t *mainbin = NULL;
4299 GstElement *autoplug_elem = NULL;
4302 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4303 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4305 mainbin = player->pipeline->mainbin;
4307 LOGD("uri type %d", player->profile.uri_type);
4309 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4310 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4311 return MM_ERROR_PLAYER_INTERNAL;
4314 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4315 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4318 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4319 if (!autoplug_elem) {
4320 LOGE("failed to create uridecodebin3 element");
4324 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4325 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4326 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4328 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4329 LOGE("failed to add uridecodebin to pipeline");
4333 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4334 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4335 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4337 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4338 LOGE("failed to create fakesink");
4341 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4343 /* take ownership of fakesink. we are reusing it */
4344 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4346 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4347 LOGE("failed to add fakesink to bin");
4348 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4353 return MM_ERROR_NONE;
4357 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4358 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4360 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4361 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4363 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4364 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4366 return MM_ERROR_PLAYER_INTERNAL;
4370 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4372 mmplayer_gst_element_t *mainbin = NULL;
4373 GstElement *src_elem = NULL;
4374 GstElement *autoplug_elem = NULL;
4375 GList *element_bucket = NULL;
4376 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4379 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4380 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4382 LOGD("uri type %d", player->profile.uri_type);
4384 /* create source element */
4385 switch (player->profile.uri_type) {
4386 case MM_PLAYER_URI_TYPE_URL_RTSP:
4387 src_elem = __mmplayer_gst_make_rtsp_src(player);
4389 case MM_PLAYER_URI_TYPE_URL_HTTP:
4390 src_elem = __mmplayer_gst_make_http_src(player);
4392 case MM_PLAYER_URI_TYPE_FILE:
4393 src_elem = __mmplayer_gst_make_file_src(player);
4395 case MM_PLAYER_URI_TYPE_SS:
4397 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4398 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4400 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4404 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4405 LOGD("get timeout from ini");
4406 http_timeout = player->ini.http_timeout;
4409 /* setting property to streaming source */
4410 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4413 case MM_PLAYER_URI_TYPE_MEM:
4415 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4417 src_elem = gst_element_factory_make("appsrc", "mem-source");
4419 LOGE("failed to create appsrc element");
4423 g_object_set(src_elem, "stream-type", stream_type,
4424 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4426 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4427 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4428 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4429 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4433 LOGE("not support uri type");
4438 LOGE("failed to create source element");
4439 return MM_ERROR_PLAYER_INTERNAL;
4442 mainbin = player->pipeline->mainbin;
4444 /* take source element */
4445 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4447 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4448 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4449 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4451 /* create next element for auto-plugging */
4452 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4453 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4454 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4455 if (!autoplug_elem) {
4456 LOGE("failed to create typefind element");
4460 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4461 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4462 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4463 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4464 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4465 if (!autoplug_elem) {
4466 LOGE("failed to create decodebin");
4470 /* default size of mq in decodebin is 2M
4471 * but it can cause blocking issue during seeking depends on content. */
4472 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4475 if (autoplug_elem) {
4476 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4477 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4478 mainbin[autoplug_elem_id].gst = autoplug_elem;
4480 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4483 /* add elements to pipeline */
4484 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4485 LOGE("failed to add elements to pipeline");
4489 /* linking elements in the bucket by added order. */
4490 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4491 LOGE("failed to link some elements");
4495 /* FIXME: need to check whether this is required or not. */
4496 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4497 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4498 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4499 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4500 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4502 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4503 LOGE("failed to create fakesink");
4506 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4508 /* take ownership of fakesink. we are reusing it */
4509 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4511 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4512 LOGE("failed to add fakesink to bin");
4513 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4518 g_list_free(element_bucket);
4521 return MM_ERROR_NONE;
4524 g_list_free(element_bucket);
4526 if (mainbin[MMPLAYER_M_SRC].gst)
4527 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4529 if (mainbin[autoplug_elem_id].gst)
4530 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4532 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4533 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4535 mainbin[MMPLAYER_M_SRC].gst = NULL;
4536 mainbin[autoplug_elem_id].gst = NULL;
4537 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4539 return MM_ERROR_PLAYER_INTERNAL;
4543 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4546 mmplayer_gst_element_t *mainbin = NULL;
4549 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4550 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4552 mainbin = player->pipeline->mainbin;
4554 /* connect bus callback */
4555 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4557 LOGE("cannot get bus from pipeline");
4558 return MM_ERROR_PLAYER_INTERNAL;
4561 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4562 (GstBusFunc)__mmplayer_gst_msg_push, player,
4563 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4564 if (player->bus_watcher == 0) {
4565 LOGE("failed to add bus watch");
4566 return MM_ERROR_PLAYER_INTERNAL;
4569 g_mutex_init(&player->bus_watcher_mutex);
4570 g_cond_init(&player->bus_watcher_cond);
4572 player->context.thread_default = g_main_context_get_thread_default();
4573 if (player->context.thread_default == NULL) {
4574 player->context.thread_default = g_main_context_default();
4575 LOGD("thread-default context is the global default context");
4577 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4579 /* set sync handler to get tag synchronously */
4580 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4581 gst_object_unref(GST_OBJECT(bus));
4583 /* create gst bus_msb_cb thread */
4584 g_mutex_init(&player->bus_msg_thread_mutex);
4585 g_cond_init(&player->bus_msg_thread_cond);
4586 player->bus_msg_thread_exit = FALSE;
4587 player->bus_msg_thread =
4588 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4589 if (!player->bus_msg_thread) {
4590 LOGE("failed to create gst BUS msg thread");
4591 g_mutex_clear(&player->bus_msg_thread_mutex);
4592 g_cond_clear(&player->bus_msg_thread_cond);
4593 return MM_ERROR_PLAYER_INTERNAL;
4597 return MM_ERROR_NONE;
4601 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4603 int ret = MM_ERROR_NONE;
4604 mmplayer_gst_element_t *mainbin = NULL;
4605 MMMessageParamType msg_param = {0,};
4606 GstElement *element = NULL;
4607 MMHandleType attrs = 0;
4609 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4613 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4614 LOGE("player is not initialized");
4618 mainbin = player->pipeline->mainbin;
4619 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4621 attrs = MMPLAYER_GET_ATTRS(player);
4623 LOGE("fail to get attributes");
4627 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4629 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4630 LOGE("failed to parse profile");
4631 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4635 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4636 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4637 LOGE("dash or hls is not supportable");
4638 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4642 if (!MMPLAYER_USE_DECODEBIN(player)) {
4643 ret = _mmplayer_gst_build_pipeline_with_src(player);
4644 if (ret != MM_ERROR_NONE)
4647 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4648 LOGE("Failed to change state of uridecodebin3 element");
4654 element = _mmplayer_gst_create_source(player);
4656 LOGE("no source element was created");
4660 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4661 LOGE("failed to add source element to pipeline");
4662 gst_object_unref(GST_OBJECT(element));
4667 /* take source element */
4668 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4669 mainbin[MMPLAYER_M_SRC].gst = element;
4673 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4674 if (player->streamer == NULL) {
4675 player->streamer = _mm_player_streaming_create();
4676 _mm_player_streaming_initialize(player->streamer, TRUE);
4679 elem_idx = MMPLAYER_M_TYPEFIND;
4680 element = gst_element_factory_make("typefind", "typefinder");
4681 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4682 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4684 elem_idx = MMPLAYER_M_AUTOPLUG;
4685 element = _mmplayer_gst_make_decodebin(player);
4688 /* check autoplug element is OK */
4690 LOGE("can not create element(%d)", elem_idx);
4694 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4695 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4696 gst_object_unref(GST_OBJECT(element));
4701 mainbin[elem_idx].id = elem_idx;
4702 mainbin[elem_idx].gst = element;
4704 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4705 LOGE("Failed to link src - autoplug(or typefind)");
4709 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4710 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4711 LOGE("Failed to change state of src element");
4715 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4716 LOGE("Failed to change state of decodebin");
4721 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4722 LOGE("Failed to change state of src element");
4727 player->gapless.stream_changed = TRUE;
4728 player->gapless.running = TRUE;
4734 _mmplayer_set_reconfigure_state(player, FALSE);
4735 if (!player->msg_posted) {
4736 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4737 player->msg_posted = TRUE;