4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
58 /* check whether the error is posted from not-activated track or not */
60 gint active_index = 0;
62 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
64 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
65 LOGD("current active pad index -%d", active_index);
67 if (src_element_name) {
70 if (player->audio_decoders) {
71 GList *adec = player->audio_decoders;
72 for (; adec ; adec = g_list_next(adec)) {
73 gchar *name = adec->data;
75 LOGD("found audio decoder name = %s", name);
76 if (g_strrstr(name, src_element_name)) {
83 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
86 if (active_index != msg_src_pos) {
87 LOGD("skip error because error is posted from no activated track");
95 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
97 /* Demuxer can't parse one track because it's corrupted.
98 * So, the decoder for it is not linked.
99 * But, it has one playable track.
101 if (g_strrstr(klass, "Demux")) {
102 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
103 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
104 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
105 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
107 if (player->pipeline->audiobin) { // PCM
108 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
110 LOGD("not found any available codec. Player should be destroyed.");
111 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
116 return MM_ERROR_PLAYER_INVALID_STREAM;
120 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
122 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
123 LOGE("Not supported subtitle.");
124 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
126 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
130 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
132 /* Decoder Custom Message */
133 if (!strstr(error->message, "ongoing"))
134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
136 if (strncasecmp(klass, "audio", 5)) {
137 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
138 LOGD("Video can keep playing.");
139 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
141 } else if (strncasecmp(klass, "video", 5)) {
142 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
143 LOGD("Audio can keep playing.");
144 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
148 LOGD("not found any available codec. Player should be destroyed.");
149 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
153 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
155 if (strstr(error->message, "rights expired"))
156 return MM_ERROR_PLAYER_DRM_EXPIRED;
157 else if (strstr(error->message, "no rights"))
158 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
159 else if (strstr(error->message, "has future rights"))
160 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
161 else if (strstr(error->message, "opl violation"))
162 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
164 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
167 /* NOTE : decide gstreamer state whether there is some playable track or not. */
169 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
171 gchar *src_element_name = NULL;
172 GstElement *src_element = NULL;
173 GstElementFactory *factory = NULL;
174 const gchar *klass = NULL;
178 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
179 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
180 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
181 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
183 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
185 src_element = GST_ELEMENT_CAST(message->src);
186 src_element_name = GST_ELEMENT_NAME(src_element);
187 if (!src_element_name)
188 return MM_ERROR_PLAYER_INTERNAL;
190 factory = gst_element_get_factory(src_element);
192 return MM_ERROR_PLAYER_INTERNAL;
194 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
196 return MM_ERROR_PLAYER_INTERNAL;
198 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
199 error->code, error->message, src_element_name, klass);
201 if (MMPLAYER_USE_DECODEBIN(player) &&
202 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
203 return MM_ERROR_NONE;
205 switch (error->code) {
206 case GST_STREAM_ERROR_DECODE:
207 return __mmplayer_gst_transform_error_decode(player, klass);
208 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
209 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
210 case GST_STREAM_ERROR_WRONG_TYPE:
211 return __mmplayer_gst_transform_error_type(player, src_element);
212 case GST_STREAM_ERROR_FAILED:
213 return __mmplayer_gst_transform_error_failed(player, klass, error);
214 case GST_STREAM_ERROR_DECRYPT:
215 case GST_STREAM_ERROR_DECRYPT_NOKEY:
216 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
217 return __mmplayer_gst_transform_error_decrypt(player, error);
224 return MM_ERROR_PLAYER_INVALID_STREAM;
228 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
230 gint trans_err = MM_ERROR_NONE;
234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 case GST_CORE_ERROR_MISSING_PLUGIN:
238 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
239 case GST_CORE_ERROR_STATE_CHANGE:
240 case GST_CORE_ERROR_SEEK:
241 case GST_CORE_ERROR_NOT_IMPLEMENTED:
242 case GST_CORE_ERROR_FAILED:
243 case GST_CORE_ERROR_TOO_LAZY:
244 case GST_CORE_ERROR_PAD:
245 case GST_CORE_ERROR_THREAD:
246 case GST_CORE_ERROR_NEGOTIATION:
247 case GST_CORE_ERROR_EVENT:
248 case GST_CORE_ERROR_CAPS:
249 case GST_CORE_ERROR_TAG:
250 case GST_CORE_ERROR_CLOCK:
251 case GST_CORE_ERROR_DISABLED:
253 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
263 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
265 gint trans_err = MM_ERROR_NONE;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
272 case GST_LIBRARY_ERROR_FAILED:
273 case GST_LIBRARY_ERROR_TOO_LAZY:
274 case GST_LIBRARY_ERROR_INIT:
275 case GST_LIBRARY_ERROR_SHUTDOWN:
276 case GST_LIBRARY_ERROR_SETTINGS:
277 case GST_LIBRARY_ERROR_ENCODE:
279 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
289 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
291 gint trans_err = MM_ERROR_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
298 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
299 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
301 case GST_RESOURCE_ERROR_NOT_FOUND:
302 case GST_RESOURCE_ERROR_OPEN_READ:
303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
304 || MMPLAYER_IS_RTSP_STREAMING(player)) {
305 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
308 case GST_RESOURCE_ERROR_READ:
309 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
310 || MMPLAYER_IS_RTSP_STREAMING(player)) {
311 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
313 } else if (message != NULL && message->src != NULL) {
314 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
315 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
317 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
318 path_type = MMPLAYER_PATH_VOD;
319 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
320 path_type = MMPLAYER_PATH_TEXT;
322 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
323 /* check storage state */
324 storage_get_state(player->storage_info[path_type].id, &storage_state);
325 player->storage_info[path_type].state = storage_state;
326 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
329 case GST_RESOURCE_ERROR_WRITE:
330 case GST_RESOURCE_ERROR_FAILED:
331 case GST_RESOURCE_ERROR_SEEK:
332 case GST_RESOURCE_ERROR_TOO_LAZY:
333 case GST_RESOURCE_ERROR_BUSY:
334 case GST_RESOURCE_ERROR_OPEN_WRITE:
335 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
336 case GST_RESOURCE_ERROR_CLOSE:
337 case GST_RESOURCE_ERROR_SYNC:
338 case GST_RESOURCE_ERROR_SETTINGS:
340 trans_err = MM_ERROR_PLAYER_INTERNAL;
350 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
352 gint trans_err = MM_ERROR_NONE;
356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
358 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
360 switch (error->code) {
361 case GST_STREAM_ERROR_FAILED:
362 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
363 case GST_STREAM_ERROR_DECODE:
364 case GST_STREAM_ERROR_WRONG_TYPE:
365 case GST_STREAM_ERROR_DECRYPT:
366 case GST_STREAM_ERROR_DECRYPT_NOKEY:
367 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
368 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
371 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
372 case GST_STREAM_ERROR_TOO_LAZY:
373 case GST_STREAM_ERROR_ENCODE:
374 case GST_STREAM_ERROR_DEMUX:
375 case GST_STREAM_ERROR_MUX:
376 case GST_STREAM_ERROR_FORMAT:
378 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
388 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
390 MMMessageParamType msg_param;
391 gchar *msg_src_element;
395 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
396 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
398 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
400 memset(&msg_param, 0, sizeof(MMMessageParamType));
402 if (error->domain == GST_CORE_ERROR) {
403 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
404 } else if (error->domain == GST_LIBRARY_ERROR) {
405 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
406 } else if (error->domain == GST_RESOURCE_ERROR) {
407 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
408 } else if (error->domain == GST_STREAM_ERROR) {
409 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
411 LOGW("This error domain is not defined.");
413 /* we treat system error as an internal error */
414 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
418 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
420 msg_param.data = (void *)error->message;
422 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
423 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
427 if (msg_param.code == MM_ERROR_NONE)
430 /* skip error to avoid duplicated posting */
431 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
432 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
433 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
434 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
436 /* The error will be handled by mused.
437 * @ref _mmplayer_manage_external_storage_state() */
439 LOGW("storage is removed, skip error post");
443 /* post error to application */
444 if (!player->msg_posted) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
446 /* don't post more if one was sent already */
447 player->msg_posted = TRUE;
449 LOGD("skip error post because it's sent already.");
458 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
461 MMMessageParamType msg_param = {0, };
462 gchar *msg_src_element = NULL;
466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
467 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
468 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
470 switch (error->code) {
471 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
472 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
474 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
475 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
477 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
478 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
480 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
481 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
483 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
484 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
486 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
487 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
489 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
490 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
492 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
493 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
495 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
498 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
501 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
504 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
507 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
510 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
513 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
516 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
519 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
522 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
525 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
528 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
531 case MMPLAYER_STREAMING_ERROR_GONE:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
534 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
540 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
543 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
546 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
549 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
552 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
555 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
558 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
561 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
564 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
567 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
570 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
573 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
576 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
579 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
582 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
585 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
588 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
591 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
594 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
597 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
600 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
603 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
608 return MM_ERROR_PLAYER_STREAMING_FAIL;
613 msg_param.data = (void *)(error->message);
616 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
618 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
619 msg_src_element, msg_param.code, (char *)msg_param.data);
622 /* post error to application */
623 if (!player->msg_posted) {
624 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
626 /* don't post more if one was sent already */
627 player->msg_posted = TRUE;
629 LOGD("skip error post because it's sent already.");
638 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
640 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
641 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
642 gst_tag_list_get_string(tags, "stitching_software",
643 &metadata->stitching_software);
644 gst_tag_list_get_string(tags, "projection_type",
645 &metadata->projection_type_string);
646 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
647 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
648 gst_tag_list_get_int(tags, "init_view_heading",
649 &metadata->init_view_heading);
650 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
651 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
652 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
653 gst_tag_list_get_int(tags, "full_pano_width_pixels",
654 &metadata->full_pano_width_pixels);
655 gst_tag_list_get_int(tags, "full_pano_height_pixels",
656 &metadata->full_pano_height_pixels);
657 gst_tag_list_get_int(tags, "cropped_area_image_width",
658 &metadata->cropped_area_image_width);
659 gst_tag_list_get_int(tags, "cropped_area_image_height",
660 &metadata->cropped_area_image_height);
661 gst_tag_list_get_int(tags, "cropped_area_left",
662 &metadata->cropped_area_left);
663 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
664 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
665 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
666 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
670 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
673 /* macro for better code readability */
674 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
676 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
677 if (string != NULL) { \
678 SECURE_LOGD("update tag string : %s", string); \
679 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
680 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
681 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
682 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
683 mm_player_set_attribute((MMHandleType)player, NULL,\
684 playertag, new_string, strlen(new_string), NULL); \
685 MMPLAYER_FREEIF(new_string); \
687 mm_player_set_attribute((MMHandleType)player, NULL,\
688 playertag, string, strlen(string), NULL); \
690 MMPLAYER_FREEIF(string); \
695 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
697 GstSample *sample = NULL;\
698 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
699 GstMapInfo info = GST_MAP_INFO_INIT;\
700 buffer = gst_sample_get_buffer(sample);\
701 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
702 LOGD("failed to get image data from tag");\
703 gst_sample_unref(sample);\
706 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
707 MMPLAYER_FREEIF(player->album_art);\
708 player->album_art = (gchar *)g_malloc(info.size);\
709 if (player->album_art) {\
710 memcpy(player->album_art, info.data, info.size);\
711 mm_player_set_attribute((MMHandleType)player, NULL,\
712 playertag, (void *)player->album_art, info.size, NULL); \
713 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
714 msg_param.data = (void *)player->album_art;\
715 msg_param.size = info.size;\
716 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
717 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
720 gst_buffer_unmap(buffer, &info);\
721 gst_sample_unref(sample);\
725 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
730 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
731 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
732 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
733 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
734 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
736 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
737 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
738 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
739 mm_player_set_attribute((MMHandleType)player, NULL,\
740 "content_audio_bitrate", v_uint, NULL); \
741 player->bitrate[track_type] = v_uint; \
742 player->total_bitrate = 0; \
743 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
744 player->total_bitrate += player->bitrate[i]; \
745 mm_player_set_attribute((MMHandleType)player, NULL,\
746 playertag, player->total_bitrate, NULL); \
747 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
748 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
749 player->maximum_bitrate[track_type] = v_uint; \
750 player->total_maximum_bitrate = 0; \
751 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
752 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, player->total_maximum_bitrate, NULL); \
755 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
757 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
764 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
766 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
768 string = g_strdup_printf("%d", g_date_get_year(date));\
769 mm_player_set_attribute((MMHandleType)player, NULL,\
770 playertag, string, strlen(string), NULL); \
771 SECURE_LOGD("metainfo year : %s", string);\
772 MMPLAYER_FREEIF(string);\
778 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
780 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
781 if (datetime != NULL) {\
782 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, string, strlen(string), NULL); \
785 SECURE_LOGD("metainfo year : %s", string);\
786 MMPLAYER_FREEIF(string);\
787 gst_date_time_unref(datetime);\
793 GstTagList *tag_list = NULL;
798 GstDateTime *datetime = NULL;
800 GstBuffer *buffer = NULL;
802 MMMessageParamType msg_param = {0, };
804 /* currently not used. but those are needed for above macro */
805 //guint64 v_uint64 = 0;
806 //gdouble v_double = 0;
808 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
810 /* get tag list from gst message */
811 gst_message_parse_tag(msg, &tag_list);
813 /* store tags to player attributes */
814 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
815 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
816 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
817 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
818 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
819 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
821 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
823 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
827 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
828 MMPLAYER_UPDATE_TAG_LOCK(player);
829 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
830 MMPLAYER_UPDATE_TAG_UNLOCK(player);
831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
833 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
834 if (player->video360_metadata.is_spherical == -1) {
835 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
836 mm_player_set_attribute((MMHandleType)player, NULL,
837 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
838 if (player->video360_metadata.is_spherical == 1) {
839 LOGD("This is spherical content for 360 playback.");
840 player->is_content_spherical = TRUE;
842 LOGD("This is not spherical content");
843 player->is_content_spherical = FALSE;
846 if (player->video360_metadata.projection_type_string) {
847 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
848 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
850 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
851 player->is_content_spherical = player->is_video360_enabled = FALSE;
855 if (player->video360_metadata.stereo_mode_string) {
856 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
857 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
858 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
859 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
860 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
861 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
863 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
864 player->is_content_spherical = player->is_video360_enabled = FALSE;
870 gst_tag_list_unref(tag_list);
876 static mmplayer_track_type_e
877 __mmplayer_convert_gst_stream_type_to_track_type (GstStreamType stype)
880 case GST_STREAM_TYPE_AUDIO:
881 return MM_PLAYER_TRACK_TYPE_AUDIO;
882 case GST_STREAM_TYPE_VIDEO:
883 return MM_PLAYER_TRACK_TYPE_VIDEO;
884 case GST_STREAM_TYPE_TEXT:
885 return MM_PLAYER_TRACK_TYPE_TEXT;
887 LOGD("not supported stream stype");
888 return MM_PLAYER_TRACK_TYPE_MAX;
892 /* if retval is FALSE, it will be dropped for performance. */
894 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
896 gboolean retval = FALSE;
898 if (!(player->pipeline && player->pipeline->mainbin)) {
899 LOGE("player pipeline handle is null");
903 switch (GST_MESSAGE_TYPE(message)) {
904 case GST_MESSAGE_TAG:
905 case GST_MESSAGE_EOS:
906 case GST_MESSAGE_ERROR:
907 case GST_MESSAGE_WARNING:
908 case GST_MESSAGE_CLOCK_LOST:
909 case GST_MESSAGE_NEW_CLOCK:
910 case GST_MESSAGE_ELEMENT:
911 case GST_MESSAGE_DURATION_CHANGED:
912 case GST_MESSAGE_ASYNC_START:
913 case GST_MESSAGE_STREAM_COLLECTION:
916 case GST_MESSAGE_ASYNC_DONE:
917 case GST_MESSAGE_STATE_CHANGED:
918 /* we only handle messages from pipeline */
919 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
924 case GST_MESSAGE_BUFFERING:
926 gint buffer_percent = 0;
929 gst_message_parse_buffering(message, &buffer_percent);
930 if (buffer_percent != MAX_BUFFER_PERCENT) {
931 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
935 if (!MMPLAYER_CMD_TRYLOCK(player)) {
936 LOGW("can't get cmd lock, send msg to bus");
940 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
941 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
942 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
945 MMPLAYER_CMD_UNLOCK(player);
949 case GST_MESSAGE_STREAMS_SELECTED:
951 if (MMPLAYER_USE_DECODEBIN(player))
952 break; /* drop msg */
953 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
954 LOGD("pipeline is still under construction for adaptive streaming");
959 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
960 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
961 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
963 gint64 dur_bytes = 0L;
965 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
966 LOGE("fail to get duration.");
968 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
969 * use file information was already set on Q2 when it was created. */
970 _mm_player_streaming_set_queue2(player->streamer,
971 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
972 TRUE, /* use_buffering */
973 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
974 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
977 LOGD("GST_MESSAGE_STREAMS_SELECTED");
978 player->no_more_pad = TRUE;
979 _mmplayer_set_reconfigure_state(player, FALSE);
980 _mmplayer_pipeline_complete(NULL, player);
993 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
995 guint64 data_size = 0;
998 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1000 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1002 if (MMPLAYER_IS_HTTP_STREAMING(player))
1003 data_size = player->http_content_size;
1005 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1006 if (!player->streamer->is_adaptive_streaming) {
1007 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1011 /* adaptivedemux2 is used for buffering in uridecodebin3 */
1012 if (!player->streamer->buffering_req.is_pre_buffering) {
1013 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
1014 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
1015 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1021 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1023 int ret = MM_ERROR_NONE;
1024 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1025 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1026 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1027 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1029 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1030 LOGW("do nothing for buffering msg");
1031 ret = MM_ERROR_PLAYER_INVALID_STATE;
1035 prev_state = MMPLAYER_PREV_STATE(player);
1036 current_state = MMPLAYER_CURRENT_STATE(player);
1037 target_state = MMPLAYER_TARGET_STATE(player);
1038 pending_state = MMPLAYER_PENDING_STATE(player);
1040 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1041 MMPLAYER_STATE_GET_NAME(prev_state),
1042 MMPLAYER_STATE_GET_NAME(current_state),
1043 MMPLAYER_STATE_GET_NAME(pending_state),
1044 MMPLAYER_STATE_GET_NAME(target_state),
1045 player->streamer->buffering_state);
1047 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1048 /* NOTE : if buffering has done, player has to go to target state. */
1049 switch (target_state) {
1050 case MM_PLAYER_STATE_PAUSED:
1052 switch (pending_state) {
1053 case MM_PLAYER_STATE_PLAYING:
1054 _mmplayer_gst_pause(player, TRUE);
1057 case MM_PLAYER_STATE_PAUSED:
1058 LOGD("player is already going to paused state, there is nothing to do.");
1061 case MM_PLAYER_STATE_NONE:
1062 case MM_PLAYER_STATE_NULL:
1063 case MM_PLAYER_STATE_READY:
1065 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1071 case MM_PLAYER_STATE_PLAYING:
1073 switch (pending_state) {
1074 case MM_PLAYER_STATE_NONE:
1076 if (current_state != MM_PLAYER_STATE_PLAYING)
1077 _mmplayer_gst_resume(player, TRUE);
1081 case MM_PLAYER_STATE_PAUSED:
1082 /* NOTE: It should be worked as asynchronously.
1083 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1085 if (current_state == MM_PLAYER_STATE_PLAYING) {
1086 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1087 * The current state should be changed to paused purposely to prevent state conflict.
1089 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1091 _mmplayer_gst_resume(player, TRUE);
1094 case MM_PLAYER_STATE_PLAYING:
1095 LOGD("player is already going to playing state, there is nothing to do.");
1098 case MM_PLAYER_STATE_NULL:
1099 case MM_PLAYER_STATE_READY:
1101 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1107 case MM_PLAYER_STATE_NULL:
1108 case MM_PLAYER_STATE_READY:
1109 case MM_PLAYER_STATE_NONE:
1111 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1115 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1116 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1118 switch (pending_state) {
1119 case MM_PLAYER_STATE_NONE:
1121 if (current_state != MM_PLAYER_STATE_PAUSED) {
1122 /* rtsp streaming pause makes rtsp server stop sending data. */
1123 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1124 LOGD("set pause state during buffering");
1125 _mmplayer_gst_pause(player, TRUE);
1131 case MM_PLAYER_STATE_PLAYING:
1132 /* rtsp streaming pause makes rtsp server stop sending data. */
1133 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1134 _mmplayer_gst_pause(player, TRUE);
1137 case MM_PLAYER_STATE_PAUSED:
1140 case MM_PLAYER_STATE_NULL:
1141 case MM_PLAYER_STATE_READY:
1143 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1152 static stream_variant_t *
1153 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1155 stream_variant_t *var_info = NULL;
1156 g_return_val_if_fail(self != NULL, NULL);
1158 var_info = g_new0(stream_variant_t, 1);
1159 if (!var_info) return NULL;
1160 var_info->bandwidth = self->bandwidth;
1161 var_info->width = self->width;
1162 var_info->height = self->height;
1167 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1173 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1174 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1176 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1177 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1178 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1180 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1181 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1182 player->http_content_size = (bytes > 0) ? bytes : 0;
1185 /* handling audio clip which has vbr. means duration is keep changing */
1186 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1195 __mmplayer_eos_timer_cb(gpointer u_data)
1197 mmplayer_t *player = NULL;
1198 MMHandleType attrs = 0;
1201 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1203 player = (mmplayer_t *)u_data;
1204 attrs = MMPLAYER_GET_ATTRS(player);
1206 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1210 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1211 if (ret_value != MM_ERROR_NONE)
1212 LOGE("seeking to 0 failed in repeat play");
1215 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1218 /* we are returning FALSE as we need only one posting */
1223 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1225 MMPLAYER_RETURN_IF_FAIL(player);
1227 /* post now if delay is zero */
1228 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1229 LOGD("eos delay is zero. posting EOS now");
1230 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1232 if (player->audio_decoded_cb)
1233 _mmplayer_cancel_eos_timer(player);
1238 /* cancel if existing */
1239 _mmplayer_cancel_eos_timer(player);
1241 /* init new timeout */
1242 /* NOTE : consider give high priority to this timer */
1243 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1245 player->eos_timer = g_timeout_add(delay_in_ms,
1246 __mmplayer_eos_timer_cb, player);
1248 player->context.global_default = g_main_context_default();
1249 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1251 /* check timer is valid. if not, send EOS now */
1252 if (player->eos_timer == 0) {
1253 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1254 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1259 __mmplayer_gst_pending_seek(mmplayer_t *player)
1261 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1262 int ret = MM_ERROR_NONE;
1266 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1268 if (!player->pending_seek.is_pending) {
1269 LOGD("pending seek is not reserved. nothing to do.");
1273 /* check player state if player could pending seek or not. */
1274 current_state = MMPLAYER_CURRENT_STATE(player);
1276 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1277 LOGW("try to pending seek in %s state, try next time. ",
1278 MMPLAYER_STATE_GET_NAME(current_state));
1282 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1284 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1285 if (ret != MM_ERROR_NONE)
1286 LOGE("failed to seek pending position. just keep staying current position.");
1288 player->pending_seek.is_pending = false;
1296 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1298 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1300 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1302 audiobin = player->pipeline->audiobin; /* can be null */
1303 videobin = player->pipeline->videobin; /* can be null */
1304 textbin = player->pipeline->textbin; /* can be null */
1306 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1308 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1309 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1311 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1312 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1314 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1315 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1321 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1323 mmplayer_gst_element_t *textbin;
1326 MMPLAYER_RETURN_IF_FAIL(player &&
1328 player->pipeline->textbin);
1330 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1332 textbin = player->pipeline->textbin;
1335 LOGD("Drop subtitle text after getting EOS");
1337 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1338 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1340 player->is_subtitle_force_drop = TRUE;
1342 if (player->is_subtitle_force_drop == TRUE) {
1343 LOGD("Enable subtitle data path without drop");
1345 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1346 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1348 LOGD("non-connected with external display");
1350 player->is_subtitle_force_drop = FALSE;
1356 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1358 MMHandleType attrs = 0;
1363 /* NOTE : EOS event is coming multiple time. watch out it */
1364 /* check state. we only process EOS when pipeline state goes to PLAYING */
1365 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1366 LOGD("EOS received on non-playing state. ignoring it");
1370 if (player->pipeline && player->pipeline->textbin)
1371 __mmplayer_drop_subtitle(player, TRUE);
1373 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1374 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1376 /* rewind if repeat count is greater then zero */
1377 /* get play count */
1378 attrs = MMPLAYER_GET_ATTRS(player);
1380 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1382 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1384 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1385 if (player->playback_rate < 0.0) {
1386 player->resumed_by_rewind = TRUE;
1387 _mmplayer_set_mute((MMHandleType)player, false);
1388 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1391 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1394 player->sent_bos = FALSE;
1396 LOGD("do not post eos msg for repeating");
1401 if (player->pipeline)
1402 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1404 /* post eos message to application */
1405 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1407 /* reset last position */
1408 player->last_position = 0;
1415 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1417 GError *error = NULL;
1418 gchar *debug = NULL;
1422 /* generating debug info before returning error */
1423 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1425 /* get error code */
1426 gst_message_parse_error(msg, &error, &debug);
1428 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1429 /* Note : the streaming error from the streaming source is handled
1430 * using __mmplayer_handle_streaming_error.
1432 __mmplayer_handle_streaming_error(player, msg, error);
1434 /* dump state of all element */
1435 _mmplayer_dump_pipeline_state(player);
1437 /* translate gst error code to msl error code. then post it
1438 * to application if needed
1440 __mmplayer_handle_gst_error(player, msg, error);
1443 LOGE("error debug : %s", debug);
1446 MMPLAYER_FREEIF(debug);
1447 g_error_free(error);
1454 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1456 MMMessageParamType msg_param = {0, };
1457 int bRet = MM_ERROR_NONE;
1460 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1462 if (!MMPLAYER_IS_STREAMING(player)) {
1463 LOGW("this is not streaming playback.");
1467 MMPLAYER_CMD_LOCK(player);
1469 if (!player->streamer) {
1470 LOGW("Pipeline is shutting down");
1471 MMPLAYER_CMD_UNLOCK(player);
1475 /* ignore the remained buffering message till getting 100% msg */
1476 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1477 gint buffer_percent = 0;
1479 gst_message_parse_buffering(msg, &buffer_percent);
1481 if (buffer_percent == MAX_BUFFER_PERCENT) {
1482 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1483 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1484 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1486 MMPLAYER_CMD_UNLOCK(player);
1490 /* ignore the remained buffering message */
1491 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1492 gint buffer_percent = 0;
1494 gst_message_parse_buffering(msg, &buffer_percent);
1496 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1497 player->streamer->buffering_percent, buffer_percent);
1499 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1500 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1501 player->streamer->buffering_req.is_pre_buffering = FALSE;
1503 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1505 LOGD("interrupted buffering - ignored the remained buffering msg!");
1506 MMPLAYER_CMD_UNLOCK(player);
1511 __mmplayer_update_buffer_setting(player, msg);
1513 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1515 if (bRet == MM_ERROR_NONE) {
1516 msg_param.connection.buffering = player->streamer->buffering_percent;
1517 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1519 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1520 player->pending_resume &&
1521 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1523 player->is_external_subtitle_added_now = FALSE;
1524 player->pending_resume = FALSE;
1525 _mmplayer_resume((MMHandleType)player);
1528 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1529 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1531 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1532 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1533 player->seek_state = MMPLAYER_SEEK_NONE;
1534 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1535 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1536 /* Considering the async state transition in case of RTSP.
1537 After getting state change gst msg, seek completed msg will be posted. */
1538 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1542 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1543 if (!player->streamer) {
1544 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1545 MMPLAYER_CMD_UNLOCK(player);
1549 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1551 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1552 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1554 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1555 msg_param.connection.buffering = player->streamer->buffering_percent;
1556 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1558 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1561 msg_param.connection.buffering = player->streamer->buffering_percent;
1562 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1565 MMPLAYER_CMD_UNLOCK(player);
1573 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1575 mmplayer_gst_element_t *mainbin;
1576 const GValue *voldstate, *vnewstate, *vpending;
1577 GstState oldstate = GST_STATE_NULL;
1578 GstState newstate = GST_STATE_NULL;
1579 GstState pending = GST_STATE_NULL;
1582 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1584 mainbin = player->pipeline->mainbin;
1586 /* we only handle messages from pipeline */
1587 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1590 /* get state info from msg */
1591 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1592 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1593 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1595 if (!voldstate || !vnewstate) {
1596 LOGE("received msg has wrong format.");
1600 oldstate = (GstState)voldstate->data[0].v_int;
1601 newstate = (GstState)vnewstate->data[0].v_int;
1603 pending = (GstState)vpending->data[0].v_int;
1605 LOGD("state changed [%s] : %s ---> %s final : %s",
1606 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1607 gst_element_state_get_name((GstState)oldstate),
1608 gst_element_state_get_name((GstState)newstate),
1609 gst_element_state_get_name((GstState)pending));
1611 if (newstate == GST_STATE_PLAYING) {
1612 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1614 int retVal = MM_ERROR_NONE;
1615 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1617 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1619 if (MM_ERROR_NONE != retVal)
1620 LOGE("failed to seek pending position. just keep staying current position.");
1622 player->pending_seek.is_pending = false;
1626 if (oldstate == newstate) {
1627 LOGD("pipeline reports state transition to old state");
1632 case GST_STATE_PAUSED:
1634 gboolean prepare_async = FALSE;
1636 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1637 // managed prepare async case
1638 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1639 LOGD("checking prepare mode for async transition - %d", prepare_async);
1642 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1643 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1645 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1646 _mm_player_streaming_set_content_bitrate(player->streamer,
1647 player->total_maximum_bitrate, player->total_bitrate);
1649 if (player->pending_seek.is_pending) {
1650 LOGW("trying to do pending seek");
1651 MMPLAYER_CMD_LOCK(player);
1652 __mmplayer_gst_pending_seek(player);
1653 MMPLAYER_CMD_UNLOCK(player);
1659 case GST_STATE_PLAYING:
1661 if (MMPLAYER_IS_STREAMING(player)) {
1662 // managed prepare async case when buffering is completed
1663 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1664 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1665 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1666 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1668 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1670 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1671 if (player->streamer->buffering_percent < 100) {
1673 MMMessageParamType msg_param = {0, };
1674 LOGW("Posting Buffering Completed Message to Application !!!");
1676 msg_param.connection.buffering = 100;
1677 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1682 if (player->gapless.stream_changed) {
1683 _mmplayer_update_content_attrs(player, ATTR_ALL);
1684 player->gapless.stream_changed = FALSE;
1687 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1688 player->seek_state = MMPLAYER_SEEK_NONE;
1689 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1693 case GST_STATE_VOID_PENDING:
1694 case GST_STATE_NULL:
1695 case GST_STATE_READY:
1705 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1707 const gchar *structure_name;
1708 gint count = 0, idx = 0;
1711 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1713 if (gst_message_get_structure(msg) == NULL)
1716 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1717 if (!structure_name)
1720 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1722 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1723 const GValue *var_info = NULL;
1725 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1726 if (var_info != NULL) {
1727 if (player->adaptive_info.var_list)
1728 g_list_free_full(player->adaptive_info.var_list, g_free);
1730 /* share addr or copy the list */
1731 player->adaptive_info.var_list =
1732 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1734 count = g_list_length(player->adaptive_info.var_list);
1736 stream_variant_t *temp = NULL;
1738 /* print out for debug */
1739 LOGD("num of variant_info %d", count);
1740 for (idx = 0; idx < count; idx++) {
1741 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1743 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1749 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1750 gint num_buffers = 0;
1751 gint extra_num_buffers = 0;
1753 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1754 LOGD("video_num_buffers : %d", num_buffers);
1755 mm_player_set_attribute((MMHandleType)player, NULL,
1756 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1759 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1760 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1761 mm_player_set_attribute((MMHandleType)player, NULL,
1762 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1767 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1768 _mmplayer_track_update_text_attr_info(player, msg);
1770 /* custom message */
1771 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1772 MMMessageParamType msg_param = {0,};
1773 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1774 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1777 /* custom message for RTSP attribute :
1778 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1779 sdp which has contents info is received when rtsp connection is opened.
1780 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1781 if (!strcmp(structure_name, "rtspsrc_properties")) {
1782 g_autofree gchar *audio_codec = NULL;
1783 g_autofree gchar *video_codec = NULL;
1784 g_autofree gchar *video_frame_size = NULL;
1786 gst_structure_get(gst_message_get_structure(msg),
1787 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1788 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1789 player->streaming_type = _mmplayer_get_stream_service_type(player);
1791 gst_structure_get(gst_message_get_structure(msg),
1792 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1793 LOGD("rtsp_audio_codec : %s", audio_codec);
1795 mm_player_set_attribute((MMHandleType)player, NULL,
1796 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1798 gst_structure_get(gst_message_get_structure(msg),
1799 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1800 LOGD("rtsp_video_codec : %s", video_codec);
1802 mm_player_set_attribute((MMHandleType)player, NULL,
1803 "content_video_codec", video_codec, strlen(video_codec), NULL);
1805 gst_structure_get(gst_message_get_structure(msg),
1806 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1807 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1808 if (video_frame_size) {
1809 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1810 mm_player_set_attribute((MMHandleType)player, NULL,
1811 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1812 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1814 g_strfreev(res_str);
1823 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1825 mmplayer_gst_element_t *mainbin;
1828 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1830 mainbin = player->pipeline->mainbin;
1832 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1834 /* we only handle messages from pipeline */
1835 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1838 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1839 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1840 player->seek_state = MMPLAYER_SEEK_NONE;
1841 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1842 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1843 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1844 LOGD("sync %s state(%s) with parent state(%s)",
1845 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1846 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1847 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1849 /* In case of streaming, pause is required before finishing seeking by buffering.
1850 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1851 Because the buffering state is controlled according to the state transition for force resume,
1852 the decodebin state should be paused as player state. */
1853 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1856 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1857 (player->streamer) &&
1858 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1859 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1860 GstQuery *query = NULL;
1861 gboolean busy = FALSE;
1864 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1865 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1866 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1867 gst_query_parse_buffering_percent(query, &busy, &percent);
1868 gst_query_unref(query);
1870 LOGD("buffered percent(%s): %d",
1871 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1875 __mmplayer_handle_buffering_playback(player);
1878 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1888 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1890 GValue val = { 0, };
1892 guint indent = GPOINTER_TO_UINT(user_data);
1894 if (!gst_tag_list_copy_value(&val, tags, tag))
1897 if (G_VALUE_HOLDS_STRING(&val))
1898 str = g_value_dup_string(&val);
1900 str = gst_value_serialize(&val);
1902 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1904 g_value_unset(&val);
1909 __mmplayer_dump_collection(GstStreamCollection * collection)
1913 GstTagList *tags = NULL;
1915 GstCaps *caps = NULL;
1917 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1918 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1919 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1920 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1921 gst_stream_get_stream_flags(stream));
1922 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1924 caps = gst_stream_get_caps(stream);
1926 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1927 gst_caps_unref(caps);
1931 tags = gst_stream_get_tags(stream);
1934 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1935 gst_tag_list_unref(tags);
1942 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1943 GstStream *stream, GParamSpec *pspec, gpointer data)
1945 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1946 gst_stream_get_stream_id(stream), pspec->name, collection);
1947 if (g_str_equal(pspec->name, "caps")) {
1948 GstCaps *caps = gst_stream_get_caps(stream);
1949 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1950 gst_caps_unref(caps);
1954 if (g_str_equal (pspec->name, "tags")) {
1955 GstTagList *tags = gst_stream_get_tags(stream);
1958 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1959 gst_tag_list_unref(tags);
1966 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1968 mmplayer_t *player = (mmplayer_t *)(data);
1970 MMPLAYER_RETURN_IF_FAIL(player);
1971 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1973 switch (GST_MESSAGE_TYPE(msg)) {
1974 case GST_MESSAGE_UNKNOWN:
1975 LOGD("unknown message received");
1978 case GST_MESSAGE_EOS:
1979 LOGD("GST_MESSAGE_EOS received");
1980 __mmplayer_gst_handle_eos_message(player, msg);
1983 case GST_MESSAGE_ERROR:
1984 _mmplayer_set_reconfigure_state(player, FALSE);
1985 __mmplayer_gst_handle_error_message(player, msg);
1988 case GST_MESSAGE_WARNING:
1991 GError *error = NULL;
1993 gst_message_parse_warning(msg, &error, &debug);
1995 LOGD("warning : %s", error->message);
1996 LOGD("debug : %s", debug);
1998 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2000 MMPLAYER_FREEIF(debug);
2001 g_error_free(error);
2005 case GST_MESSAGE_TAG:
2007 LOGD("GST_MESSAGE_TAG");
2008 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2009 LOGW("failed to extract tags from gstmessage");
2013 case GST_MESSAGE_BUFFERING:
2014 __mmplayer_gst_handle_buffering_message(player, msg);
2017 case GST_MESSAGE_STATE_CHANGED:
2018 __mmplayer_gst_handle_state_message(player, msg);
2021 case GST_MESSAGE_CLOCK_LOST:
2023 GstClock *clock = NULL;
2024 gboolean need_new_clock = FALSE;
2026 gst_message_parse_clock_lost(msg, &clock);
2027 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2029 if (!player->videodec_linked)
2030 need_new_clock = TRUE;
2031 else if (!player->ini.use_system_clock)
2032 need_new_clock = TRUE;
2034 if (need_new_clock) {
2035 LOGD("Provide clock is TRUE, do pause->resume");
2036 _mmplayer_gst_pause(player, FALSE);
2037 _mmplayer_gst_resume(player, FALSE);
2042 case GST_MESSAGE_NEW_CLOCK:
2044 GstClock *clock = NULL;
2045 gst_message_parse_new_clock(msg, &clock);
2046 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2050 case GST_MESSAGE_ELEMENT:
2051 __mmplayer_gst_handle_element_message(player, msg);
2054 case GST_MESSAGE_DURATION_CHANGED:
2056 LOGD("GST_MESSAGE_DURATION_CHANGED");
2057 if (!__mmplayer_gst_handle_duration(player, msg))
2058 LOGW("failed to update duration");
2062 case GST_MESSAGE_ASYNC_START:
2063 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2066 case GST_MESSAGE_ASYNC_DONE:
2067 __mmplayer_gst_handle_async_done_message(player, msg);
2069 case GST_MESSAGE_STREAM_COLLECTION:
2071 GstStreamCollection *collection = NULL;
2072 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2074 gst_message_parse_stream_collection(msg, &collection);
2076 __mmplayer_dump_collection(collection);
2077 if (player->collection && player->stream_notify_id) {
2078 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2079 player->stream_notify_id = 0;
2081 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2082 if (player->collection) {
2083 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2084 (GCallback)__mmplayer_stream_notify_cb, player);
2086 gst_object_unref(collection);
2089 case GST_MESSAGE_STREAMS_SELECTED:
2091 GstStreamCollection *collection = NULL;
2092 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2094 gst_message_parse_streams_selected(msg, &collection);
2096 guint len = gst_message_streams_selected_get_size(msg);
2097 for (guint i = 0; i < len; i++) {
2098 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2099 mmplayer_track_type_e type = __mmplayer_convert_gst_stream_type_to_track_type(
2100 gst_stream_get_stream_type(stream));
2101 if (type == MM_PLAYER_TRACK_TYPE_MAX) {
2102 LOGD("not supported track type");
2103 gst_object_unref(stream);
2106 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2107 if (player->track[type].active_track_index == INVALID_TRACK_INDEX) {
2108 int stream_index = INVALID_TRACK_INDEX;
2109 if (_mmplayer_get_track_index(player, type, stream, &stream_index) == MM_ERROR_NONE) {
2110 player->track[type].active_track_index = stream_index;
2111 LOGD("selected this stream, update active idx : %d",
2112 player->track[type].active_track_index);
2115 gst_object_unref(stream);
2117 gst_object_unref(collection);
2122 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2123 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2124 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2125 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2126 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2127 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2128 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2129 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2130 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2131 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2132 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2133 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2134 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2135 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2136 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2143 /* should not call 'gst_message_unref(msg)' */
2147 static GstBusSyncReply
2148 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2150 mmplayer_t *player = (mmplayer_t *)data;
2151 GstBusSyncReply reply = GST_BUS_DROP;
2153 if (!(player->pipeline && player->pipeline->mainbin)) {
2154 LOGE("player pipeline handle is null");
2155 return GST_BUS_PASS;
2158 if (!__mmplayer_gst_check_useful_message(player, message)) {
2159 gst_message_unref(message);
2160 return GST_BUS_DROP;
2163 switch (GST_MESSAGE_TYPE(message)) {
2164 case GST_MESSAGE_TAG:
2165 __mmplayer_gst_extract_tag_from_msg(player, message);
2169 GstTagList *tags = NULL;
2171 gst_message_parse_tag(message, &tags);
2173 LOGE("TAGS received from element \"%s\".",
2174 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2176 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2177 gst_tag_list_unref(tags);
2185 case GST_MESSAGE_DURATION_CHANGED:
2186 __mmplayer_gst_handle_duration(player, message);
2188 case GST_MESSAGE_ELEMENT:
2190 const gchar *klass = NULL;
2191 klass = gst_element_factory_get_metadata
2192 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2193 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2194 reply = GST_BUS_PASS;
2197 __mmplayer_gst_handle_element_message(player, message);
2200 case GST_MESSAGE_ASYNC_DONE:
2201 /* NOTE:Don't call gst_callback directly
2202 * because previous frame can be showed even though this message is received for seek.
2205 reply = GST_BUS_PASS;
2209 if (reply == GST_BUS_DROP)
2210 gst_message_unref(message);
2216 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2218 GstElement *appsrc = element;
2219 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2220 GstBuffer *buffer = NULL;
2221 GstFlowReturn ret = GST_FLOW_OK;
2224 MMPLAYER_RETURN_IF_FAIL(element);
2225 MMPLAYER_RETURN_IF_FAIL(buf);
2227 buffer = gst_buffer_new();
2229 if (buf->offset < 0 || buf->len < 0) {
2230 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2234 if (buf->offset >= buf->len) {
2235 LOGD("call eos appsrc");
2236 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2240 if (buf->len - buf->offset < size)
2241 len = buf->len - buf->offset;
2243 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2244 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2245 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2248 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2250 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2256 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2258 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2260 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2262 buf->offset = (int)size;
2268 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2270 mmplayer_t *player = (mmplayer_t *)user_data;
2271 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2272 MMMessageParamType msg_param = {0,};
2273 guint64 current_level_bytes = 0;
2275 MMPLAYER_RETURN_IF_FAIL(player);
2277 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2278 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2279 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2280 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2282 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2286 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2288 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2290 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2291 msg_param.buffer_status.stream_type = stream_type;
2292 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2293 msg_param.buffer_status.bytes = current_level_bytes;
2295 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2299 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2301 mmplayer_t *player = (mmplayer_t *)user_data;
2302 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2303 MMMessageParamType msg_param = {0,};
2304 guint64 current_level_bytes = 0;
2306 MMPLAYER_RETURN_IF_FAIL(player);
2308 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2309 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2310 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2311 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2313 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2317 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2319 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2321 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2322 msg_param.buffer_status.stream_type = stream_type;
2323 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2324 msg_param.buffer_status.bytes = current_level_bytes;
2326 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2330 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2332 mmplayer_t *player = (mmplayer_t *)user_data;
2333 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2334 MMMessageParamType msg_param = {0,};
2336 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2338 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2339 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2340 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2341 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2343 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2347 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2349 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2350 msg_param.seek_data.stream_type = stream_type;
2351 msg_param.seek_data.offset = position;
2353 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2359 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2361 #define MAX_LEN_NAME 20
2363 gboolean ret = FALSE;
2364 GstPad *sinkpad = NULL;
2365 gchar *prefix = NULL;
2366 gchar dec_name[MAX_LEN_NAME] = {0, };
2367 main_element_id_e elem_id = MMPLAYER_M_NUM;
2369 mmplayer_gst_element_t *mainbin = NULL;
2370 GstElement *decodebin = NULL;
2371 GstCaps *dec_caps = NULL;
2375 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2377 player->pipeline->mainbin, FALSE);
2378 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2380 mainbin = player->pipeline->mainbin;
2382 case MM_PLAYER_STREAM_TYPE_AUDIO:
2384 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2386 case MM_PLAYER_STREAM_TYPE_VIDEO:
2388 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2391 LOGE("invalid type %d", type);
2395 if (mainbin[elem_id].gst) {
2396 LOGE("elem(%d) is already created", elem_id);
2400 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2402 /* create decodebin */
2403 decodebin = gst_element_factory_make("decodebin", dec_name);
2405 LOGE("failed to create %s", dec_name);
2409 /* raw pad handling signal */
2410 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2411 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2413 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2414 before looking for any elements that can handle that stream.*/
2415 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2416 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2418 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2419 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2420 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2422 /* This signal is emitted when a element is added to the bin.*/
2423 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2424 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2426 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2427 LOGE("failed to add new decodebin");
2431 dec_caps = gst_pad_query_caps(srcpad, NULL);
2434 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2436 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2437 gst_caps_unref(dec_caps);
2440 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2442 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2443 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2446 gst_object_unref(GST_OBJECT(sinkpad));
2448 gst_element_sync_state_with_parent(decodebin);
2450 mainbin[elem_id].id = elem_id;
2451 mainbin[elem_id].gst = decodebin;
2458 gst_object_unref(GST_OBJECT(sinkpad));
2461 gst_element_set_state(decodebin, GST_STATE_NULL);
2462 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2463 gst_object_unref(decodebin);
2471 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2473 #define MAX_LEN_NAME 20
2474 mmplayer_gst_element_t *mainbin = NULL;
2475 gchar *prefix = NULL;
2476 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2478 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2479 GstElement *src = NULL, *queue = NULL;
2480 GstPad *srcpad = NULL;
2483 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2484 player->pipeline->mainbin, FALSE);
2486 mainbin = player->pipeline->mainbin;
2488 LOGD("type(%d) path is creating", type);
2490 case MM_PLAYER_STREAM_TYPE_AUDIO:
2492 if (mainbin[MMPLAYER_M_SRC].gst)
2493 src_id = MMPLAYER_M_2ND_SRC;
2495 src_id = MMPLAYER_M_SRC;
2496 queue_id = MMPLAYER_M_A_BUFFER;
2498 case MM_PLAYER_STREAM_TYPE_VIDEO:
2500 src_id = MMPLAYER_M_SRC;
2501 queue_id = MMPLAYER_M_V_BUFFER;
2503 case MM_PLAYER_STREAM_TYPE_TEXT:
2504 prefix = "subtitle";
2505 src_id = MMPLAYER_M_SUBSRC;
2506 queue_id = MMPLAYER_M_S_BUFFER;
2509 LOGE("invalid type %d", type);
2513 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2514 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2517 src = gst_element_factory_make("appsrc", src_name);
2519 LOGF("failed to create %s", src_name);
2523 mainbin[src_id].id = src_id;
2524 mainbin[src_id].gst = src;
2526 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2527 "caps", caps, NULL);
2529 /* size of many video frames are larger than default blocksize as 4096 */
2530 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2531 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2533 if (player->media_stream_buffer_max_size[type] > 0)
2534 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2536 if (player->media_stream_buffer_min_percent[type] > 0)
2537 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2539 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2540 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2542 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2543 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2544 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2545 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2546 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2547 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2550 queue = gst_element_factory_make("queue2", queue_name);
2552 LOGE("failed to create %s", queue_name);
2555 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2557 mainbin[queue_id].id = queue_id;
2558 mainbin[queue_id].gst = queue;
2560 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2561 LOGE("failed to add src");
2565 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2566 LOGE("failed to add queue");
2570 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2571 LOGE("failed to link src and queue");
2575 /* create decoder */
2576 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2578 LOGE("failed to get srcpad of queue");
2582 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2583 _mmplayer_gst_create_decoder(player, srcpad, caps);
2585 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2586 LOGE("failed to create decoder");
2587 gst_object_unref(GST_OBJECT(srcpad));
2591 gst_object_unref(GST_OBJECT(srcpad));
2595 if (mainbin[src_id].gst) {
2596 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2597 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2598 gst_object_unref(mainbin[src_id].gst);
2599 mainbin[src_id].gst = NULL;
2602 if (mainbin[queue_id].gst) {
2603 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2604 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2605 gst_object_unref(mainbin[queue_id].gst);
2606 mainbin[queue_id].gst = NULL;
2613 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2615 GstPad *sinkpad = NULL;
2616 GstCaps *caps = NULL;
2617 GstElement *new_element = NULL;
2618 GstStructure *str = NULL;
2619 const gchar *name = NULL;
2621 mmplayer_t *player = (mmplayer_t *)data;
2625 MMPLAYER_RETURN_IF_FAIL(element && pad);
2626 MMPLAYER_RETURN_IF_FAIL(player &&
2628 player->pipeline->mainbin);
2630 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2631 * num_dynamic_pad will decreased after creating a sinkbin.
2633 player->num_dynamic_pad++;
2634 LOGD("stream count inc : %d", player->num_dynamic_pad);
2636 caps = gst_pad_query_caps(pad, NULL);
2637 MMPLAYER_CHECK_NULL(caps);
2639 str = gst_caps_get_structure(caps, 0);
2640 name = gst_structure_get_string(str, "media");
2642 LOGE("cannot get mimetype from structure.");
2646 if (strstr(name, "video")) {
2648 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2650 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2651 if (player->v_stream_caps) {
2652 gst_caps_unref(player->v_stream_caps);
2653 player->v_stream_caps = NULL;
2656 new_element = gst_element_factory_make("fakesink", NULL);
2657 player->num_dynamic_pad--;
2662 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2663 LOGE("failed to autoplug for caps");
2667 gst_caps_unref(caps);
2672 /* execute new_element if created*/
2674 LOGD("adding new element to pipeline");
2676 /* set state to READY before add to bin */
2677 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2679 /* add new element to the pipeline */
2680 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2681 LOGE("failed to add autoplug element to bin");
2685 /* get pad from element */
2686 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2688 LOGE("failed to get sinkpad from autoplug element");
2693 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2694 LOGE("failed to link autoplug element");
2698 gst_object_unref(sinkpad);
2701 /* run. setting PLAYING here since streaming source is live source */
2702 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2706 gst_caps_unref(caps);
2712 STATE_CHANGE_FAILED:
2714 /* FIXIT : take care if new_element has already added to pipeline */
2716 gst_object_unref(GST_OBJECT(new_element));
2719 gst_object_unref(GST_OBJECT(sinkpad));
2722 gst_caps_unref(caps);
2724 /* FIXIT : how to inform this error to MSL ????? */
2725 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2726 * then post an error to application
2731 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2733 mmplayer_t *player = (mmplayer_t *)data;
2737 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2738 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2739 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2740 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2742 * [1] audio and video will be dumped with filesink.
2743 * [2] autoplugging is done by just using pad caps.
2744 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2745 * and the video will be dumped via filesink.
2747 if (player->num_dynamic_pad == 0) {
2748 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2750 if (!_mmplayer_gst_remove_fakesink(player,
2751 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2752 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2753 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2754 * source element are not same. To overcome this situation, this function will called
2755 * several places and several times. Therefore, this is not an error case.
2760 /* create dot before error-return. for debugging */
2761 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2763 player->no_more_pad = TRUE;
2769 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2771 GstElement *element = NULL;
2772 gchar *user_agent = NULL;
2773 MMHandleType attrs = 0;
2776 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2778 /* get profile attribute */
2779 attrs = MMPLAYER_GET_ATTRS(player);
2781 LOGE("failed to get content attribute");
2785 element = gst_element_factory_make("rtspsrc", "rtsp source");
2787 LOGE("failed to create rtspsrc element");
2792 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2794 SECURE_LOGD("user_agent : %s", user_agent);
2796 /* setting property to streaming source */
2797 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2799 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2801 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2802 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2803 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2804 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2810 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2812 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2814 mmplayer_t *player = (mmplayer_t *)data;
2815 MMHandleType attrs = 0;
2816 gchar *user_agent, *cookies, **cookie_list;
2817 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2818 user_agent = cookies = NULL;
2822 MMPLAYER_RETURN_IF_FAIL(player);
2824 LOGD("source element %s", GST_ELEMENT_NAME(source));
2826 attrs = MMPLAYER_GET_ATTRS(player);
2828 LOGE("failed to get content attribute");
2832 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2833 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2835 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2836 http_timeout = player->ini.http_timeout;
2838 SECURE_LOGD("cookies : %s", cookies);
2839 SECURE_LOGD("user_agent : %s", user_agent);
2840 LOGD("timeout : %d", http_timeout);
2842 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2844 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2845 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2846 g_strfreev(cookie_list);
2850 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2856 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2858 mmplayer_t *player = (mmplayer_t *)data;
2859 gchar *user_agent = NULL;
2860 MMHandleType attrs = 0;
2863 MMPLAYER_RETURN_IF_FAIL(player);
2865 attrs = MMPLAYER_GET_ATTRS(player);
2867 LOGE("failed to get content attribute");
2871 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2873 SECURE_LOGD("user_agent : %s", user_agent);
2876 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2882 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2884 mmplayer_t *player = (mmplayer_t *)data;
2885 GstElement *source = NULL;
2888 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2890 g_object_get(orig, pspec->name, &source, NULL);
2892 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2893 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2895 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2896 __mmplayer_http_src_setup(source, data);
2897 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2898 __mmplayer_rtsp_src_setup(source, data);
2899 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2900 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2901 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2902 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2903 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2905 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2906 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2907 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2908 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2910 gst_object_unref (source);
2916 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2917 GstStream * stream, gpointer data)
2919 #define RET_SELECT 1
2921 #define RET_DEPENDS_ON_DECODEBIN -1
2923 GstStreamType stype = gst_stream_get_stream_type(stream);
2924 mmplayer_t *player = (mmplayer_t *)data;
2925 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2926 g_autoptr(GstCaps) caps = gst_stream_get_caps(stream);
2927 g_autofree gchar *caps_str = NULL;
2928 GstStructure *caps_structure = NULL;
2929 int stream_index = INVALID_TRACK_INDEX;
2930 int ret = MM_ERROR_NONE;
2932 LOGD("Stream type %s flags 0x%x",
2933 gst_stream_type_get_name(stype),
2934 gst_stream_get_stream_flags(stream));
2935 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2937 type = __mmplayer_convert_gst_stream_type_to_track_type(stype);
2940 caps_str = gst_caps_to_string(caps);
2941 caps_structure = gst_caps_get_structure(caps, 0);
2942 const gchar *mime = gst_structure_get_name(caps_structure);
2944 LOGD(" caps: %s", caps_str);
2946 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2947 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2948 LOGW("skip [%s] by unsupported codec keyword [%s]",
2949 mime, player->ini.unsupported_codec_keyword[idx]);
2951 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2955 } else if (type == MM_PLAYER_TRACK_TYPE_AUDIO || type == MM_PLAYER_TRACK_TYPE_VIDEO) {
2956 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
2957 LOGD("No caps info, depends on decodebin");
2958 _mmplayer_track_update_stream(player, type, stream);
2959 return RET_DEPENDS_ON_DECODEBIN;
2962 LOGD("No caps info, skip it");
2967 case GST_STREAM_TYPE_AUDIO:
2969 if (caps_structure) {
2970 gint samplerate = 0;
2973 gst_structure_get_int(caps_structure, "rate", &samplerate);
2974 gst_structure_get_int(caps_structure, "channels", &channels);
2975 if (samplerate == 0 && channels > 0) {
2976 LOGW("Skip corrupted audio stream");
2980 if (g_strrstr(caps_str, "mobile-xmf"))
2981 mm_player_set_attribute((MMHandleType)player, NULL,
2982 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2986 case GST_STREAM_TYPE_VIDEO:
2988 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) {
2989 LOGD("do not support muti track video");
2993 // FIXME: it cause block during preparing
2994 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2997 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2998 /* don't make video because of not required */
2999 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
3000 (!player->set_mode.video_export)) {
3001 LOGD("no need video decoding, skip video stream");
3006 if (caps_structure) {
3009 gst_structure_get_int(caps_structure, "width", &width);
3011 if (player->v_stream_caps) {
3012 gst_caps_unref(player->v_stream_caps);
3013 player->v_stream_caps = NULL;
3016 player->v_stream_caps = gst_caps_copy(caps);
3017 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3022 case GST_STREAM_TYPE_TEXT:
3025 LOGW("Skip not supported stream type");
3029 _mmplayer_track_update_stream(player, type, stream);
3031 ret = _mmplayer_get_track_index(player, type, stream, &stream_index);
3033 if ((player->track[type].active_track_index == INVALID_TRACK_INDEX) &&
3034 (ret == MM_ERROR_NONE)) {
3035 player->track[type].active_track_index = stream_index;
3036 LOGD("select this stream, active track idx : %d", player->track[type].active_track_index);
3037 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3038 _mmplayer_set_audio_attrs(player, caps);
3042 if (player->track[type].active_track_index == stream_index) {
3043 LOGD("already activate track idx : %d", player->track[type].active_track_index);
3047 LOGD("Skip stream");
3052 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3053 GstStream * stream, gpointer data)
3055 mmplayer_t *player = (mmplayer_t *)data;
3056 GstStreamType stype = gst_stream_get_stream_type(stream);
3059 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3061 LOGD("stream type %s", gst_stream_type_get_name(stype));
3063 /* public does not support audio hw decoder at the moment */
3065 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3066 LOGW("video decoder resource is already acquired, skip it.");
3070 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3071 LOGE("failed to acquire video decoder resource");
3074 player->interrupted_by_resource = FALSE;
3080 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3082 GstIterator *iter = NULL;
3083 GValue item = {0, };
3084 GstElement *ch_element = NULL;
3085 GstElementFactory *ch_factory = NULL;
3088 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3090 iter = gst_bin_iterate_recurse(bin);
3091 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3093 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3094 ch_element = g_value_get_object(&item);
3095 ch_factory = gst_element_get_factory(ch_element);
3096 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3097 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3098 LOGD("Find %s element", element_name);
3102 g_value_reset(&item);
3104 gst_iterator_free(iter);
3110 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3112 mmplayer_t *player = (mmplayer_t *)data;
3114 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3116 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3117 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3118 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3120 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3121 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3122 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3125 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3127 mmplayer_t *player = (mmplayer_t *)data;
3128 int video_codec_type = 0;
3129 int audio_codec_type = 0;
3131 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3133 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3134 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3136 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3138 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3139 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3140 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3141 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3143 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3144 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3148 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3150 gchar *factory_name = NULL;
3151 mmplayer_t *player = (mmplayer_t *)data;
3154 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3156 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3158 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3160 if (g_strrstr(factory_name, "urisourcebin")) {
3161 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3163 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3165 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3167 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3169 LOGW("failed to find decodebin3");
3171 } else if (g_strrstr(factory_name, "parsebin")) {
3172 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3173 __mmplayer_parsebin_setup(GST_BIN(element), data);
3175 _mmplayer_gst_element_added(child, element, data);
3180 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3184 MMPLAYER_RETURN_IF_FAIL(player);
3185 MMPLAYER_RETURN_IF_FAIL(removed_element);
3187 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3189 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3190 GList *node = player->signals[type];
3192 GList *next_node = node->next;
3193 mmplayer_signal_item_t *item = node->data;
3194 if (item && item->obj == G_OBJECT(removed_element)) {
3195 player->signals[type] = g_list_delete_link(player->signals[type], node);
3196 MMPLAYER_FREEIF(item);
3206 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3208 mmplayer_t *player = (mmplayer_t *)data;
3212 MMPLAYER_RETURN_IF_FAIL(player);
3214 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3216 __mmplayer_delete_signal_connection(player, element);
3222 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3224 GstElement *uridecodebin3 = NULL;
3227 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3229 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3230 if (!uridecodebin3) {
3231 LOGE("failed to create uridecodebin3");
3236 SECURE_LOGD("uri : %s", player->profile.uri);
3238 /* setting property to streaming source */
3239 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3240 "message-forward", TRUE,
3241 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3242 "use-buffering", TRUE, NULL);
3244 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3245 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3247 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3248 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3250 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3251 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3253 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3254 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3256 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3257 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3259 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3260 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3262 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3263 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3265 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3266 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3268 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3269 LOGW("[DASH] this is still experimental feature");
3272 return uridecodebin3;
3276 __mmplayer_gst_make_http_src(mmplayer_t *player)
3278 #define MAX_RETRY_COUNT 10
3279 GstElement *element = NULL;
3280 MMHandleType attrs = 0;
3281 gchar *user_agent, *cookies, **cookie_list;
3282 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3284 user_agent = cookies = NULL;
3288 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3290 /* get profile attribute */
3291 attrs = MMPLAYER_GET_ATTRS(player);
3293 LOGE("failed to get content attribute");
3297 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3299 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3301 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3306 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3307 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3309 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3310 http_timeout = player->ini.http_timeout;
3313 SECURE_LOGD("location : %s", player->profile.uri);
3314 SECURE_LOGD("cookies : %s", cookies);
3315 SECURE_LOGD("user_agent : %s", user_agent);
3316 LOGD("timeout : %d", http_timeout);
3318 /* setting property to streaming source */
3319 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3320 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3321 "retries", MAX_RETRY_COUNT, NULL);
3323 /* parsing cookies */
3324 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3325 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3326 g_strfreev(cookie_list);
3330 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3332 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3333 LOGW("[DASH] this is still experimental feature");
3340 __mmplayer_gst_make_file_src(mmplayer_t *player)
3342 GstElement *element = NULL;
3345 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3347 LOGD("using filesrc for 'file://' handler");
3348 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3349 LOGE("failed to get storage info");
3353 element = gst_element_factory_make("filesrc", "source");
3355 LOGE("failed to create filesrc");
3359 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3366 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3368 mmplayer_t *player = (mmplayer_t *)data;
3370 g_return_val_if_fail(player, FALSE);
3371 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3372 gst_message_ref(msg);
3374 g_mutex_lock(&player->bus_msg_q_lock);
3375 g_queue_push_tail(player->bus_msg_q, msg);
3376 g_mutex_unlock(&player->bus_msg_q_lock);
3378 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3379 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3380 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3384 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3386 mmplayer_t *player = (mmplayer_t *)(data);
3387 GstMessage *msg = NULL;
3390 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3392 player->pipeline->mainbin &&
3393 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3396 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3398 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3399 while (!player->bus_msg_thread_exit) {
3400 g_mutex_lock(&player->bus_msg_q_lock);
3401 msg = g_queue_pop_head(player->bus_msg_q);
3402 g_mutex_unlock(&player->bus_msg_q_lock);
3404 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3407 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3408 /* handle the gst msg */
3409 __mmplayer_gst_bus_msg_callback(msg, player);
3410 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3411 gst_message_unref(msg);
3414 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3421 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3423 gint64 dur_nsec = 0;
3424 gint64 pos_nsec = 0;
3427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3429 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3430 return MM_ERROR_NONE;
3432 /* NOTE : duration cannot be zero except live streaming.
3433 * Since some element could have some timing problem with querying duration, try again.
3435 if (player->duration == 0) {
3436 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3437 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3438 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3439 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3440 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3441 player->pending_seek.is_pending = true;
3442 player->pending_seek.pos = position;
3443 player->seek_state = MMPLAYER_SEEK_NONE;
3444 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3445 return MM_ERROR_PLAYER_NO_OP;
3447 player->seek_state = MMPLAYER_SEEK_NONE;
3448 return MM_ERROR_PLAYER_SEEK;
3451 player->duration = dur_nsec;
3454 if (player->duration > 0 && player->duration < position) {
3455 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3456 return MM_ERROR_INVALID_ARGUMENT;
3459 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3460 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3461 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3462 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3463 player->seek_state = MMPLAYER_SEEK_NONE;
3464 return MM_ERROR_PLAYER_NO_OP;
3469 return MM_ERROR_NONE;
3473 __mmplayer_gst_check_seekable(mmplayer_t *player)
3475 GstQuery *query = NULL;
3476 gboolean seekable = FALSE;
3478 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3482 query = gst_query_new_seeking(GST_FORMAT_TIME);
3483 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3484 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3485 gst_query_unref(query);
3488 LOGW("non-seekable content");
3489 player->seek_state = MMPLAYER_SEEK_NONE;
3493 LOGW("failed to get seeking query");
3494 gst_query_unref(query); /* keep seeking operation */
3501 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3503 GstState element_state = GST_STATE_VOID_PENDING;
3504 GstState element_pending_state = GST_STATE_VOID_PENDING;
3505 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3509 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3510 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3512 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3515 ret = gst_element_set_state(element, state);
3516 if (ret == GST_STATE_CHANGE_FAILURE) {
3517 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3519 /* dump state of all element */
3520 _mmplayer_dump_pipeline_state(player);
3522 return MM_ERROR_PLAYER_INTERNAL;
3525 /* return here so state transition to be done in async mode */
3527 LOGD("async state transition. not waiting for state complete.");
3528 return MM_ERROR_NONE;
3531 /* wait for state transition */
3532 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3533 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3534 LOGE("failed to change [%s] element state to [%s] within %d sec",
3535 GST_ELEMENT_NAME(element),
3536 gst_element_state_get_name(state), timeout);
3538 LOGE(" [%s] state : %s pending : %s",
3539 GST_ELEMENT_NAME(element),
3540 gst_element_state_get_name(element_state),
3541 gst_element_state_get_name(element_pending_state));
3543 /* dump state of all element */
3544 _mmplayer_dump_pipeline_state(player);
3546 return MM_ERROR_PLAYER_INTERNAL;
3549 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3553 return MM_ERROR_NONE;
3557 _mmplayer_gst_start(mmplayer_t *player)
3559 int ret = MM_ERROR_NONE;
3560 gboolean async = FALSE;
3564 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3566 /* NOTE : if SetPosition was called before Start. do it now
3567 * streaming doesn't support it. so it should be always sync
3568 * !!create one more api to check if there is pending seek rather than checking variables
3570 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3571 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3572 ret = _mmplayer_gst_pause(player, FALSE);
3573 if (ret != MM_ERROR_NONE) {
3574 LOGE("failed to set state to PAUSED for pending seek");
3578 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3579 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3580 LOGW("failed to seek pending position. starting from the begin of content");
3583 LOGD("current state before doing transition");
3584 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3585 MMPLAYER_PRINT_STATE(player);
3587 /* set pipeline state to PLAYING */
3588 ret = _mmplayer_gst_set_state(player,
3589 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3590 if (ret != MM_ERROR_NONE) {
3591 LOGE("failed to set state to PLAYING");
3595 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3597 /* generating debug info before returning error */
3598 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3606 _mmplayer_gst_stop(mmplayer_t *player)
3608 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3609 MMHandleType attrs = 0;
3610 gboolean rewind = FALSE;
3612 int ret = MM_ERROR_NONE;
3616 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3617 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3619 LOGD("current state before doing transition");
3620 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3621 MMPLAYER_PRINT_STATE(player);
3623 attrs = MMPLAYER_GET_ATTRS(player);
3625 LOGE("cannot get content attribute");
3626 return MM_ERROR_PLAYER_INTERNAL;
3629 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3630 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3632 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3633 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3636 if (player->es_player_push_mode)
3637 /* disable the async state transition because there could be no data in the pipeline */
3638 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3641 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3643 if (player->es_player_push_mode) {
3644 /* enable the async state transition as default operation */
3645 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3648 /* return if set_state has failed */
3649 if (ret != MM_ERROR_NONE) {
3650 LOGE("failed to set state.");
3656 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3657 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3658 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3659 LOGW("failed to rewind");
3660 ret = MM_ERROR_PLAYER_SEEK;
3665 player->sent_bos = FALSE;
3667 if (player->es_player_push_mode) //for cloudgame
3670 /* wait for seek to complete */
3671 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3672 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3673 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3675 LOGE("fail to stop player.");
3676 ret = MM_ERROR_PLAYER_INTERNAL;
3677 _mmplayer_dump_pipeline_state(player);
3680 /* generate dot file if enabled */
3681 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3689 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3691 int ret = MM_ERROR_NONE;
3695 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3696 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3698 LOGD("current state before doing transition");
3699 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3700 MMPLAYER_PRINT_STATE(player);
3702 /* set pipeline status to PAUSED */
3703 ret = _mmplayer_gst_set_state(player,
3704 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3709 if (ret != MM_ERROR_NONE) {
3710 GstMessage *msg = NULL;
3711 GTimer *timer = NULL;
3712 gdouble MAX_TIMEOUT_SEC = 3;
3714 LOGE("failed to set state to PAUSED");
3716 if (!player->bus_watcher) {
3717 LOGE("there is no bus msg thread. pipeline is shutting down.");
3721 if (player->msg_posted) {
3722 LOGE("error msg is already posted.");
3726 timer = g_timer_new();
3727 g_timer_start(timer);
3729 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3732 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3734 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3735 GError *error = NULL;
3737 /* parse error code */
3738 gst_message_parse_error(msg, &error, NULL);
3740 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3741 /* Note : the streaming error from the streaming source is handled
3742 * using __mmplayer_handle_streaming_error.
3744 __mmplayer_handle_streaming_error(player, msg, error);
3747 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3749 if (error->domain == GST_STREAM_ERROR)
3750 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3751 else if (error->domain == GST_RESOURCE_ERROR)
3752 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3753 else if (error->domain == GST_LIBRARY_ERROR)
3754 ret = __mmplayer_gst_handle_library_error(player, error->code);
3755 else if (error->domain == GST_CORE_ERROR)
3756 ret = __mmplayer_gst_handle_core_error(player, error->code);
3758 g_error_free(error);
3760 player->msg_posted = TRUE;
3762 gst_message_unref(msg);
3764 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3766 gst_object_unref(bus);
3767 g_timer_stop(timer);
3768 g_timer_destroy(timer);
3773 if (MMPLAYER_USE_DECODEBIN(player)) {
3774 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3775 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3776 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3779 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3782 /* generate dot file before returning error */
3783 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3791 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3793 int ret = MM_ERROR_NONE;
3798 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3799 MM_ERROR_PLAYER_NOT_INITIALIZED);
3801 LOGD("current state before doing transition");
3802 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3803 MMPLAYER_PRINT_STATE(player);
3806 LOGD("do async state transition to PLAYING");
3808 /* set pipeline state to PLAYING */
3809 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3811 ret = _mmplayer_gst_set_state(player,
3812 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3813 if (ret != MM_ERROR_NONE) {
3814 LOGE("failed to set state to PLAYING");
3819 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3822 /* generate dot file */
3823 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3830 /* sending event to one of sinkelements */
3832 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3834 GstEvent *event2 = NULL;
3835 GList *sinks = NULL;
3836 gboolean res = FALSE;
3839 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3840 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3842 /* While adding subtitles in live feeds seek is getting called.
3843 Adding defensive check in framework layer.*/
3844 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3845 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3846 LOGE("Should not send seek event during live playback");
3851 if (player->play_subtitle)
3852 event2 = gst_event_copy((const GstEvent *)event);
3854 sinks = player->sink_elements;
3856 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3858 if (GST_IS_ELEMENT(sink)) {
3859 /* keep ref to the event */
3860 gst_event_ref(event);
3862 if ((res = gst_element_send_event(sink, event))) {
3863 LOGD("sending event[%s] to sink element [%s] success!",
3864 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3866 /* rtsp case, async_done is not called after seek during pause state */
3867 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3868 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3869 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3870 LOGD("RTSP seek completed, after pause state..");
3871 player->seek_state = MMPLAYER_SEEK_NONE;
3872 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3878 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3879 sinks = g_list_next(sinks);
3886 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3887 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3890 sinks = g_list_next(sinks);
3893 /* Note : Textbin is not linked to the video or audio bin.
3894 * It needs to send the event to the text sink separately.
3896 if (player->play_subtitle && player->pipeline) {
3897 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3899 if (GST_IS_ELEMENT(text_sink)) {
3900 /* keep ref to the event */
3901 gst_event_ref(event2);
3903 if ((res = gst_element_send_event(text_sink, event2)))
3904 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3905 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3907 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3908 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3910 gst_event_unref(event2);
3914 gst_event_unref(event);
3922 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3923 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3924 gint64 cur, GstSeekType stop_type, gint64 stop)
3926 GstEvent *event = NULL;
3927 gboolean result = FALSE;
3931 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3933 if (player->pipeline && player->pipeline->textbin)
3934 __mmplayer_drop_subtitle(player, FALSE);
3936 event = gst_event_new_seek(rate, format, flags, cur_type,
3937 cur, stop_type, stop);
3939 result = _mmplayer_gst_send_event_to_sink(player, event);
3947 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3949 int ret = MM_ERROR_NONE;
3950 gint64 pos_nsec = 0;
3951 gboolean accurate = FALSE;
3952 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3956 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3958 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3959 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3962 ret = __mmplayer_gst_check_position(player, position);
3963 if (ret != MM_ERROR_NONE) {
3964 LOGW("result of check position info 0x%X", ret);
3965 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3968 if (!__mmplayer_gst_check_seekable(player))
3969 return MM_ERROR_PLAYER_NO_OP;
3971 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3972 position, player->playback_rate, player->duration);
3974 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3975 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3976 This causes problem is position calculation during normal pause resume scenarios also.
3977 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3978 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3979 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3980 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3981 LOGW("getting current position failed in seek");
3983 player->last_position = pos_nsec;
3984 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3987 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3988 LOGD("not completed seek");
3989 return MM_ERROR_PLAYER_DOING_SEEK;
3992 if (!internal_called)
3993 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3995 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3996 that's why set position through property. */
3997 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3998 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3999 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
4000 (!player->videodec_linked) && (!player->audiodec_linked)) {
4002 LOGD("[%s] set position =%"GST_TIME_FORMAT,
4003 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
4005 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
4006 player->seek_state = MMPLAYER_SEEK_NONE;
4007 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4009 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4011 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4013 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4015 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4016 GST_FORMAT_TIME, seek_flags,
4017 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4018 LOGE("failed to set position");
4023 /* NOTE : store last seeking point to overcome some bad operation
4024 * (returning zero when getting current position) of some elements
4026 player->last_position = position;
4028 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4029 if (player->playback_rate > 1.0)
4030 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4032 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4033 LOGD("buffering should be reset after seeking");
4034 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4035 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4039 return MM_ERROR_NONE;
4042 player->pending_seek.is_pending = true;
4043 player->pending_seek.pos = position;
4045 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4046 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4047 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4048 player->pending_seek.pos);
4050 return MM_ERROR_NONE;
4053 player->seek_state = MMPLAYER_SEEK_NONE;
4054 return MM_ERROR_PLAYER_SEEK;
4058 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4060 #define TRICKPLAY_OFFSET GST_MSECOND
4062 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4063 gint64 pos_nsec = 0;
4064 gboolean ret = TRUE;
4066 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4067 MM_ERROR_PLAYER_NOT_INITIALIZED);
4069 current_state = MMPLAYER_CURRENT_STATE(player);
4071 /* NOTE : query position except paused state to overcome some bad operation
4072 * please refer to below comments in details
4074 if (current_state != MM_PLAYER_STATE_PAUSED)
4075 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4077 /* NOTE : get last point to overcome some bad operation of some elements
4078 *(returning zero when getting current position in paused state
4079 * and when failed to get position during seeking
4081 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4082 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4084 if (player->playback_rate < 0.0)
4085 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4087 pos_nsec = player->last_position;
4090 pos_nsec = player->last_position;
4092 player->last_position = pos_nsec;
4094 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4097 if (player->duration > 0 && pos_nsec > player->duration)
4098 pos_nsec = player->duration;
4100 player->last_position = pos_nsec;
4103 *position = pos_nsec;
4105 return MM_ERROR_NONE;
4109 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4111 #define STREAMING_IS_FINISHED 0
4112 #define BUFFERING_MAX_PER 100
4113 #define DEFAULT_PER_VALUE -1
4114 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4116 mmplayer_gst_element_t *mainbin = NULL;
4117 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4118 gint64 buffered_total = 0;
4119 gint64 position = 0;
4120 gint buffered_sec = -1;
4121 GstBufferingMode mode = GST_BUFFERING_STREAM;
4122 gint64 content_size_time = player->duration;
4123 guint64 content_size_bytes = player->http_content_size;
4125 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4127 player->pipeline->mainbin,
4128 MM_ERROR_PLAYER_NOT_INITIALIZED);
4130 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4135 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4136 /* and rtsp is not ready yet. */
4137 LOGW("it's only used for http streaming case");
4138 return MM_ERROR_PLAYER_NO_OP;
4141 if (content_size_time <= 0 || content_size_bytes <= 0) {
4142 LOGW("there is no content size");
4143 return MM_ERROR_NONE;
4146 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4147 LOGW("fail to get current position");
4148 return MM_ERROR_NONE;
4151 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4152 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4154 mainbin = player->pipeline->mainbin;
4155 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4157 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4158 GstQuery *query = NULL;
4159 gint byte_in_rate = 0, byte_out_rate = 0;
4160 gint64 estimated_total = 0;
4162 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4163 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4164 LOGW("fail to get buffering query from queue2");
4166 gst_query_unref(query);
4167 return MM_ERROR_NONE;
4170 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4171 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4173 if (mode == GST_BUFFERING_STREAM) {
4174 /* using only queue in case of push mode(ts / mp3) */
4175 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4176 GST_FORMAT_BYTES, &buffered_total)) {
4177 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4178 end_per = 100 * buffered_total / content_size_bytes;
4181 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4183 guint num_of_ranges = 0;
4184 gint64 start_byte = 0, stop_byte = 0;
4186 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4187 if (estimated_total != STREAMING_IS_FINISHED) {
4188 /* buffered size info from queue2 */
4189 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4190 for (idx = 0; idx < num_of_ranges; idx++) {
4191 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4192 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4194 buffered_total += (stop_byte - start_byte);
4197 end_per = BUFFERING_MAX_PER;
4200 gst_query_unref(query);
4203 if (end_per == DEFAULT_PER_VALUE) {
4204 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4206 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4208 /* buffered size info from multiqueue */
4209 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4210 guint curr_size_bytes = 0;
4211 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4212 "curr-size-bytes", &curr_size_bytes, NULL);
4213 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4214 buffered_total += (gint64)curr_size_bytes;
4217 if (avg_byterate > 0)
4218 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4219 else if (player->total_maximum_bitrate > 0)
4220 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4221 else if (player->total_bitrate > 0)
4222 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4224 if (buffered_sec >= 0)
4225 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4229 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4230 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4232 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4233 buffered_total, buffered_sec, *start_pos, *end_pos);
4235 return MM_ERROR_NONE;
4239 _mmplayer_gst_create_source(mmplayer_t *player)
4241 GstElement *element = NULL;
4244 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4245 player->pipeline->mainbin, NULL);
4247 /* setup source for gapless play */
4248 switch (player->profile.uri_type) {
4250 case MM_PLAYER_URI_TYPE_FILE:
4251 element = __mmplayer_gst_make_file_src(player);
4253 case MM_PLAYER_URI_TYPE_URL_HTTP:
4254 element = __mmplayer_gst_make_http_src(player);
4257 LOGE("not support uri type %d", player->profile.uri_type);
4262 LOGE("failed to create source element");
4271 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4275 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4277 SECURE_LOGD("uri : %s", player->profile.uri);
4279 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4281 if ((player->v_stream_caps) &&
4282 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4283 return MM_ERROR_PLAYER_INTERNAL;
4285 if ((player->a_stream_caps) &&
4286 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4287 return MM_ERROR_PLAYER_INTERNAL;
4289 if ((player->s_stream_caps) &&
4290 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4291 return MM_ERROR_PLAYER_INTERNAL;
4294 return MM_ERROR_NONE;
4298 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4300 mmplayer_gst_element_t *mainbin = NULL;
4301 GstElement *autoplug_elem = NULL;
4304 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4305 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4307 mainbin = player->pipeline->mainbin;
4309 LOGD("uri type %d", player->profile.uri_type);
4311 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4312 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4313 return MM_ERROR_PLAYER_INTERNAL;
4316 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4317 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4320 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4321 if (!autoplug_elem) {
4322 LOGE("failed to create uridecodebin3 element");
4326 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4327 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4328 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4330 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4331 LOGE("failed to add uridecodebin to pipeline");
4335 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4336 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4337 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4339 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4340 LOGE("failed to create fakesink");
4343 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4345 /* take ownership of fakesink. we are reusing it */
4346 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4348 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4349 LOGE("failed to add fakesink to bin");
4350 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4355 return MM_ERROR_NONE;
4359 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4360 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4362 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4363 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4365 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4366 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4368 return MM_ERROR_PLAYER_INTERNAL;
4372 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4374 mmplayer_gst_element_t *mainbin = NULL;
4375 GstElement *src_elem = NULL;
4376 GstElement *autoplug_elem = NULL;
4377 GList *element_bucket = NULL;
4378 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4381 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4382 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4384 LOGD("uri type %d", player->profile.uri_type);
4386 /* create source element */
4387 switch (player->profile.uri_type) {
4388 case MM_PLAYER_URI_TYPE_URL_RTSP:
4389 src_elem = __mmplayer_gst_make_rtsp_src(player);
4391 case MM_PLAYER_URI_TYPE_URL_HTTP:
4392 src_elem = __mmplayer_gst_make_http_src(player);
4394 case MM_PLAYER_URI_TYPE_FILE:
4395 src_elem = __mmplayer_gst_make_file_src(player);
4397 case MM_PLAYER_URI_TYPE_SS:
4399 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4400 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4402 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4406 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4407 LOGD("get timeout from ini");
4408 http_timeout = player->ini.http_timeout;
4411 /* setting property to streaming source */
4412 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4415 case MM_PLAYER_URI_TYPE_MEM:
4417 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4419 src_elem = gst_element_factory_make("appsrc", "mem-source");
4421 LOGE("failed to create appsrc element");
4425 g_object_set(src_elem, "stream-type", stream_type,
4426 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4428 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4429 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4430 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4431 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4435 LOGE("not support uri type");
4440 LOGE("failed to create source element");
4441 return MM_ERROR_PLAYER_INTERNAL;
4444 mainbin = player->pipeline->mainbin;
4446 /* take source element */
4447 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4449 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4450 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4451 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4453 /* create next element for auto-plugging */
4454 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4455 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4456 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4457 if (!autoplug_elem) {
4458 LOGE("failed to create typefind element");
4462 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4463 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4464 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4465 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4466 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4467 if (!autoplug_elem) {
4468 LOGE("failed to create decodebin");
4472 /* default size of mq in decodebin is 2M
4473 * but it can cause blocking issue during seeking depends on content. */
4474 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4477 if (autoplug_elem) {
4478 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4479 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4480 mainbin[autoplug_elem_id].gst = autoplug_elem;
4482 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4485 /* add elements to pipeline */
4486 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4487 LOGE("failed to add elements to pipeline");
4491 /* linking elements in the bucket by added order. */
4492 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4493 LOGE("failed to link some elements");
4497 /* FIXME: need to check whether this is required or not. */
4498 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4499 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4500 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4501 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4502 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4504 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4505 LOGE("failed to create fakesink");
4508 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4510 /* take ownership of fakesink. we are reusing it */
4511 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4513 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4514 LOGE("failed to add fakesink to bin");
4515 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4520 g_list_free(element_bucket);
4523 return MM_ERROR_NONE;
4526 g_list_free(element_bucket);
4528 if (mainbin[MMPLAYER_M_SRC].gst)
4529 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4531 if (mainbin[autoplug_elem_id].gst)
4532 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4534 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4535 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4537 mainbin[MMPLAYER_M_SRC].gst = NULL;
4538 mainbin[autoplug_elem_id].gst = NULL;
4539 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4541 return MM_ERROR_PLAYER_INTERNAL;
4545 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4548 mmplayer_gst_element_t *mainbin = NULL;
4551 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4552 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4554 mainbin = player->pipeline->mainbin;
4556 /* connect bus callback */
4557 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4559 LOGE("cannot get bus from pipeline");
4560 return MM_ERROR_PLAYER_INTERNAL;
4563 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4564 (GstBusFunc)__mmplayer_gst_msg_push, player,
4565 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4566 if (player->bus_watcher == 0) {
4567 LOGE("failed to add bus watch");
4568 return MM_ERROR_PLAYER_INTERNAL;
4571 g_mutex_init(&player->bus_watcher_mutex);
4572 g_cond_init(&player->bus_watcher_cond);
4574 player->context.thread_default = g_main_context_get_thread_default();
4575 if (player->context.thread_default == NULL) {
4576 player->context.thread_default = g_main_context_default();
4577 LOGD("thread-default context is the global default context");
4579 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4581 /* set sync handler to get tag synchronously */
4582 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4583 gst_object_unref(GST_OBJECT(bus));
4585 /* create gst bus_msb_cb thread */
4586 g_mutex_init(&player->bus_msg_thread_mutex);
4587 g_cond_init(&player->bus_msg_thread_cond);
4588 player->bus_msg_thread_exit = FALSE;
4589 player->bus_msg_thread =
4590 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4591 if (!player->bus_msg_thread) {
4592 LOGE("failed to create gst BUS msg thread");
4593 g_mutex_clear(&player->bus_msg_thread_mutex);
4594 g_cond_clear(&player->bus_msg_thread_cond);
4595 return MM_ERROR_PLAYER_INTERNAL;
4599 return MM_ERROR_NONE;
4603 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4605 int ret = MM_ERROR_NONE;
4606 mmplayer_gst_element_t *mainbin = NULL;
4607 MMMessageParamType msg_param = {0,};
4608 GstElement *element = NULL;
4609 MMHandleType attrs = 0;
4611 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4615 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4616 LOGE("player is not initialized");
4620 mainbin = player->pipeline->mainbin;
4621 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4623 attrs = MMPLAYER_GET_ATTRS(player);
4625 LOGE("fail to get attributes");
4629 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4631 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4632 LOGE("failed to parse profile");
4633 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4637 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4638 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4639 LOGE("dash or hls is not supportable");
4640 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4644 if (!MMPLAYER_USE_DECODEBIN(player)) {
4645 ret = _mmplayer_gst_build_pipeline_with_src(player);
4646 if (ret != MM_ERROR_NONE)
4649 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4650 LOGE("Failed to change state of uridecodebin3 element");
4656 element = _mmplayer_gst_create_source(player);
4658 LOGE("no source element was created");
4662 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4663 LOGE("failed to add source element to pipeline");
4664 gst_object_unref(GST_OBJECT(element));
4669 /* take source element */
4670 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4671 mainbin[MMPLAYER_M_SRC].gst = element;
4675 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4676 if (player->streamer == NULL) {
4677 player->streamer = _mm_player_streaming_create();
4678 _mm_player_streaming_initialize(player->streamer, TRUE);
4681 elem_idx = MMPLAYER_M_TYPEFIND;
4682 element = gst_element_factory_make("typefind", "typefinder");
4683 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4684 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4686 elem_idx = MMPLAYER_M_AUTOPLUG;
4687 element = _mmplayer_gst_make_decodebin(player);
4690 /* check autoplug element is OK */
4692 LOGE("can not create element(%d)", elem_idx);
4696 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4697 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4698 gst_object_unref(GST_OBJECT(element));
4703 mainbin[elem_idx].id = elem_idx;
4704 mainbin[elem_idx].gst = element;
4706 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4707 LOGE("Failed to link src - autoplug(or typefind)");
4711 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4712 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4713 LOGE("Failed to change state of src element");
4717 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4718 LOGE("Failed to change state of decodebin");
4723 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4724 LOGE("Failed to change state of src element");
4729 player->gapless.stream_changed = TRUE;
4730 player->gapless.running = TRUE;
4736 _mmplayer_set_reconfigure_state(player, FALSE);
4737 if (!player->msg_posted) {
4738 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4739 player->msg_posted = TRUE;