4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
58 /* check whether the error is posted from not-activated track or not */
60 gint active_index = 0;
62 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
64 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
65 LOGD("current active pad index -%d", active_index);
67 if (src_element_name) {
70 if (player->audio_decoders) {
71 GList *adec = player->audio_decoders;
72 for (; adec ; adec = g_list_next(adec)) {
73 gchar *name = adec->data;
75 LOGD("found audio decoder name = %s", name);
76 if (g_strrstr(name, src_element_name)) {
83 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
86 if (active_index != msg_src_pos) {
87 LOGD("skip error because error is posted from no activated track");
95 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
97 /* Demuxer can't parse one track because it's corrupted.
98 * So, the decoder for it is not linked.
99 * But, it has one playable track.
101 if (g_strrstr(klass, "Demux")) {
102 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
103 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
104 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
105 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
107 if (player->pipeline->audiobin) { // PCM
108 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
110 LOGD("not found any available codec. Player should be destroyed.");
111 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
116 return MM_ERROR_PLAYER_INVALID_STREAM;
120 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
122 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
123 LOGE("Not supported subtitle.");
124 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
126 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
130 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
132 /* Decoder Custom Message */
133 if (!strstr(error->message, "ongoing"))
134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
136 if (strncasecmp(klass, "audio", 5)) {
137 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
138 LOGD("Video can keep playing.");
139 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
141 } else if (strncasecmp(klass, "video", 5)) {
142 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
143 LOGD("Audio can keep playing.");
144 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
148 LOGD("not found any available codec. Player should be destroyed.");
149 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
153 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
155 if (strstr(error->message, "rights expired"))
156 return MM_ERROR_PLAYER_DRM_EXPIRED;
157 else if (strstr(error->message, "no rights"))
158 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
159 else if (strstr(error->message, "has future rights"))
160 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
161 else if (strstr(error->message, "opl violation"))
162 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
164 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
167 /* NOTE : decide gstreamer state whether there is some playable track or not. */
169 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
171 gchar *src_element_name = NULL;
172 GstElement *src_element = NULL;
173 GstElementFactory *factory = NULL;
174 const gchar *klass = NULL;
178 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
179 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
180 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
181 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
183 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
185 src_element = GST_ELEMENT_CAST(message->src);
186 src_element_name = GST_ELEMENT_NAME(src_element);
187 if (!src_element_name)
188 return MM_ERROR_PLAYER_INTERNAL;
190 factory = gst_element_get_factory(src_element);
192 return MM_ERROR_PLAYER_INTERNAL;
194 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
196 return MM_ERROR_PLAYER_INTERNAL;
198 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
199 error->code, error->message, src_element_name, klass);
201 if (MMPLAYER_USE_DECODEBIN(player) &&
202 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
203 return MM_ERROR_NONE;
205 switch (error->code) {
206 case GST_STREAM_ERROR_DECODE:
207 return __mmplayer_gst_transform_error_decode(player, klass);
208 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
209 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
210 case GST_STREAM_ERROR_WRONG_TYPE:
211 return __mmplayer_gst_transform_error_type(player, src_element);
212 case GST_STREAM_ERROR_FAILED:
213 return __mmplayer_gst_transform_error_failed(player, klass, error);
214 case GST_STREAM_ERROR_DECRYPT:
215 case GST_STREAM_ERROR_DECRYPT_NOKEY:
216 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
217 return __mmplayer_gst_transform_error_decrypt(player, error);
224 return MM_ERROR_PLAYER_INVALID_STREAM;
228 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
230 gint trans_err = MM_ERROR_NONE;
234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 case GST_CORE_ERROR_MISSING_PLUGIN:
238 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
239 case GST_CORE_ERROR_STATE_CHANGE:
240 case GST_CORE_ERROR_SEEK:
241 case GST_CORE_ERROR_NOT_IMPLEMENTED:
242 case GST_CORE_ERROR_FAILED:
243 case GST_CORE_ERROR_TOO_LAZY:
244 case GST_CORE_ERROR_PAD:
245 case GST_CORE_ERROR_THREAD:
246 case GST_CORE_ERROR_NEGOTIATION:
247 case GST_CORE_ERROR_EVENT:
248 case GST_CORE_ERROR_CAPS:
249 case GST_CORE_ERROR_TAG:
250 case GST_CORE_ERROR_CLOCK:
251 case GST_CORE_ERROR_DISABLED:
253 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
263 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
265 gint trans_err = MM_ERROR_NONE;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
272 case GST_LIBRARY_ERROR_FAILED:
273 case GST_LIBRARY_ERROR_TOO_LAZY:
274 case GST_LIBRARY_ERROR_INIT:
275 case GST_LIBRARY_ERROR_SHUTDOWN:
276 case GST_LIBRARY_ERROR_SETTINGS:
277 case GST_LIBRARY_ERROR_ENCODE:
279 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
289 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
291 gint trans_err = MM_ERROR_NONE;
295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
298 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
299 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
301 case GST_RESOURCE_ERROR_NOT_FOUND:
302 case GST_RESOURCE_ERROR_OPEN_READ:
303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
304 || MMPLAYER_IS_RTSP_STREAMING(player)) {
305 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
308 case GST_RESOURCE_ERROR_READ:
309 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
310 || MMPLAYER_IS_RTSP_STREAMING(player)) {
311 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
313 } else if (message != NULL && message->src != NULL) {
314 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
315 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
317 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
318 path_type = MMPLAYER_PATH_VOD;
319 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
320 path_type = MMPLAYER_PATH_TEXT;
322 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
323 /* check storage state */
324 storage_get_state(player->storage_info[path_type].id, &storage_state);
325 player->storage_info[path_type].state = storage_state;
326 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
329 case GST_RESOURCE_ERROR_WRITE:
330 case GST_RESOURCE_ERROR_FAILED:
331 case GST_RESOURCE_ERROR_SEEK:
332 case GST_RESOURCE_ERROR_TOO_LAZY:
333 case GST_RESOURCE_ERROR_BUSY:
334 case GST_RESOURCE_ERROR_OPEN_WRITE:
335 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
336 case GST_RESOURCE_ERROR_CLOSE:
337 case GST_RESOURCE_ERROR_SYNC:
338 case GST_RESOURCE_ERROR_SETTINGS:
340 trans_err = MM_ERROR_PLAYER_INTERNAL;
350 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
352 gint trans_err = MM_ERROR_NONE;
356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
357 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
358 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
360 switch (error->code) {
361 case GST_STREAM_ERROR_FAILED:
362 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
363 case GST_STREAM_ERROR_DECODE:
364 case GST_STREAM_ERROR_WRONG_TYPE:
365 case GST_STREAM_ERROR_DECRYPT:
366 case GST_STREAM_ERROR_DECRYPT_NOKEY:
367 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
368 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
371 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
372 case GST_STREAM_ERROR_TOO_LAZY:
373 case GST_STREAM_ERROR_ENCODE:
374 case GST_STREAM_ERROR_DEMUX:
375 case GST_STREAM_ERROR_MUX:
376 case GST_STREAM_ERROR_FORMAT:
378 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
388 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
390 MMMessageParamType msg_param;
391 gchar *msg_src_element;
395 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
396 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
398 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
400 memset(&msg_param, 0, sizeof(MMMessageParamType));
402 if (error->domain == GST_CORE_ERROR) {
403 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
404 } else if (error->domain == GST_LIBRARY_ERROR) {
405 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
406 } else if (error->domain == GST_RESOURCE_ERROR) {
407 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
408 } else if (error->domain == GST_STREAM_ERROR) {
409 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
411 LOGW("This error domain is not defined.");
413 /* we treat system error as an internal error */
414 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
418 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
420 msg_param.data = (void *)error->message;
422 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
423 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
427 if (msg_param.code == MM_ERROR_NONE)
430 /* skip error to avoid duplicated posting */
431 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
432 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
433 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
434 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
436 /* The error will be handled by mused.
437 * @ref _mmplayer_manage_external_storage_state() */
439 LOGW("storage is removed, skip error post");
443 /* post error to application */
444 if (!player->msg_posted) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
446 /* don't post more if one was sent already */
447 player->msg_posted = TRUE;
449 LOGD("skip error post because it's sent already.");
458 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
461 MMMessageParamType msg_param = {0, };
462 gchar *msg_src_element = NULL;
466 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
467 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
468 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
470 switch (error->code) {
471 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
472 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
474 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
475 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
477 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
478 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
480 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
481 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
483 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
484 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
486 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
487 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
489 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
490 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
492 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
493 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
495 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
496 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
498 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
499 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
501 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
502 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
504 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
505 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
507 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
508 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
510 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
511 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
513 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
514 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
516 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
517 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
519 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
520 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
522 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
523 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
525 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
526 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
528 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
529 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
531 case MMPLAYER_STREAMING_ERROR_GONE:
532 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
534 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
535 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
537 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
538 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
540 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
541 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
543 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
544 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
546 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
547 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
549 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
550 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
552 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
553 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
555 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
556 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
558 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
559 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
561 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
562 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
564 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
565 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
567 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
570 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
571 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
573 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
574 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
576 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
577 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
579 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
582 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
583 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
585 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
588 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
589 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
591 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
592 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
594 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
595 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
597 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
598 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
600 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
601 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
603 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
604 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
608 return MM_ERROR_PLAYER_STREAMING_FAIL;
613 msg_param.data = (void *)(error->message);
616 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
618 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
619 msg_src_element, msg_param.code, (char *)msg_param.data);
622 /* post error to application */
623 if (!player->msg_posted) {
624 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
626 /* don't post more if one was sent already */
627 player->msg_posted = TRUE;
629 LOGD("skip error post because it's sent already.");
638 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
640 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
641 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
642 gst_tag_list_get_string(tags, "stitching_software",
643 &metadata->stitching_software);
644 gst_tag_list_get_string(tags, "projection_type",
645 &metadata->projection_type_string);
646 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
647 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
648 gst_tag_list_get_int(tags, "init_view_heading",
649 &metadata->init_view_heading);
650 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
651 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
652 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
653 gst_tag_list_get_int(tags, "full_pano_width_pixels",
654 &metadata->full_pano_width_pixels);
655 gst_tag_list_get_int(tags, "full_pano_height_pixels",
656 &metadata->full_pano_height_pixels);
657 gst_tag_list_get_int(tags, "cropped_area_image_width",
658 &metadata->cropped_area_image_width);
659 gst_tag_list_get_int(tags, "cropped_area_image_height",
660 &metadata->cropped_area_image_height);
661 gst_tag_list_get_int(tags, "cropped_area_left",
662 &metadata->cropped_area_left);
663 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
664 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
665 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
666 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
670 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
673 /* macro for better code readability */
674 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
676 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
677 if (string != NULL) { \
678 SECURE_LOGD("update tag string : %s", string); \
679 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
680 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
681 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
682 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
683 mm_player_set_attribute((MMHandleType)player, NULL,\
684 playertag, new_string, strlen(new_string), NULL); \
685 MMPLAYER_FREEIF(new_string); \
687 mm_player_set_attribute((MMHandleType)player, NULL,\
688 playertag, string, strlen(string), NULL); \
690 MMPLAYER_FREEIF(string); \
695 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
697 GstSample *sample = NULL;\
698 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
699 GstMapInfo info = GST_MAP_INFO_INIT;\
700 buffer = gst_sample_get_buffer(sample);\
701 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
702 LOGD("failed to get image data from tag");\
703 gst_sample_unref(sample);\
706 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
707 MMPLAYER_FREEIF(player->album_art);\
708 player->album_art = (gchar *)g_malloc(info.size);\
709 if (player->album_art) {\
710 memcpy(player->album_art, info.data, info.size);\
711 mm_player_set_attribute((MMHandleType)player, NULL,\
712 playertag, (void *)player->album_art, info.size, NULL); \
713 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
714 msg_param.data = (void *)player->album_art;\
715 msg_param.size = info.size;\
716 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
717 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
720 gst_buffer_unmap(buffer, &info);\
721 gst_sample_unref(sample);\
725 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
730 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
731 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
732 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
733 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
734 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
736 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
737 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
738 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
739 mm_player_set_attribute((MMHandleType)player, NULL,\
740 "content_audio_bitrate", v_uint, NULL); \
741 player->bitrate[track_type] = v_uint; \
742 player->total_bitrate = 0; \
743 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
744 player->total_bitrate += player->bitrate[i]; \
745 mm_player_set_attribute((MMHandleType)player, NULL,\
746 playertag, player->total_bitrate, NULL); \
747 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
748 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
749 player->maximum_bitrate[track_type] = v_uint; \
750 player->total_maximum_bitrate = 0; \
751 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
752 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, player->total_maximum_bitrate, NULL); \
755 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
757 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
764 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
766 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
768 string = g_strdup_printf("%d", g_date_get_year(date));\
769 mm_player_set_attribute((MMHandleType)player, NULL,\
770 playertag, string, strlen(string), NULL); \
771 SECURE_LOGD("metainfo year : %s", string);\
772 MMPLAYER_FREEIF(string);\
778 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
780 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
781 if (datetime != NULL) {\
782 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
783 mm_player_set_attribute((MMHandleType)player, NULL,\
784 playertag, string, strlen(string), NULL); \
785 SECURE_LOGD("metainfo year : %s", string);\
786 MMPLAYER_FREEIF(string);\
787 gst_date_time_unref(datetime);\
793 GstTagList *tag_list = NULL;
798 GstDateTime *datetime = NULL;
800 GstBuffer *buffer = NULL;
802 MMMessageParamType msg_param = {0, };
804 /* currently not used. but those are needed for above macro */
805 //guint64 v_uint64 = 0;
806 //gdouble v_double = 0;
808 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
810 /* get tag list from gst message */
811 gst_message_parse_tag(msg, &tag_list);
813 /* store tags to player attributes */
814 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
815 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
816 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
817 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
818 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
819 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
820 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
821 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
822 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
823 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
824 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
826 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
827 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
828 MMPLAYER_UPDATE_TAG_LOCK(player);
829 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
830 MMPLAYER_UPDATE_TAG_UNLOCK(player);
831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
833 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
834 if (player->video360_metadata.is_spherical == -1) {
835 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
836 mm_player_set_attribute((MMHandleType)player, NULL,
837 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
838 if (player->video360_metadata.is_spherical == 1) {
839 LOGD("This is spherical content for 360 playback.");
840 player->is_content_spherical = TRUE;
842 LOGD("This is not spherical content");
843 player->is_content_spherical = FALSE;
846 if (player->video360_metadata.projection_type_string) {
847 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
848 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
850 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
851 player->is_content_spherical = player->is_video360_enabled = FALSE;
855 if (player->video360_metadata.stereo_mode_string) {
856 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
857 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
858 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
859 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
860 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
861 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
863 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
864 player->is_content_spherical = player->is_video360_enabled = FALSE;
870 gst_tag_list_unref(tag_list);
875 /* if retval is FALSE, it will be dropped for performance. */
877 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
879 gboolean retval = FALSE;
881 if (!(player->pipeline && player->pipeline->mainbin)) {
882 LOGE("player pipeline handle is null");
886 switch (GST_MESSAGE_TYPE(message)) {
887 case GST_MESSAGE_TAG:
888 case GST_MESSAGE_EOS:
889 case GST_MESSAGE_ERROR:
890 case GST_MESSAGE_WARNING:
891 case GST_MESSAGE_CLOCK_LOST:
892 case GST_MESSAGE_NEW_CLOCK:
893 case GST_MESSAGE_ELEMENT:
894 case GST_MESSAGE_DURATION_CHANGED:
895 case GST_MESSAGE_ASYNC_START:
896 case GST_MESSAGE_STREAM_COLLECTION:
899 case GST_MESSAGE_ASYNC_DONE:
900 case GST_MESSAGE_STATE_CHANGED:
901 /* we only handle messages from pipeline */
902 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
907 case GST_MESSAGE_BUFFERING:
909 gint buffer_percent = 0;
912 gst_message_parse_buffering(message, &buffer_percent);
913 if (buffer_percent != MAX_BUFFER_PERCENT) {
914 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
918 if (!MMPLAYER_CMD_TRYLOCK(player)) {
919 LOGW("can't get cmd lock, send msg to bus");
923 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
924 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
925 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
928 MMPLAYER_CMD_UNLOCK(player);
932 case GST_MESSAGE_STREAMS_SELECTED:
934 if (MMPLAYER_USE_DECODEBIN(player))
935 break; /* drop msg */
936 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
937 LOGD("pipeline is still under construction for adaptive streaming");
942 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
943 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
944 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
946 gint64 dur_bytes = 0L;
948 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
949 LOGE("fail to get duration.");
951 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
952 * use file information was already set on Q2 when it was created. */
953 _mm_player_streaming_set_queue2(player->streamer,
954 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
955 TRUE, /* use_buffering */
956 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
957 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
960 LOGD("GST_MESSAGE_STREAMS_SELECTED");
961 player->no_more_pad = TRUE;
962 _mmplayer_set_reconfigure_state(player, FALSE);
963 _mmplayer_pipeline_complete(NULL, player);
976 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
978 guint64 data_size = 0;
981 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
983 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
985 if (MMPLAYER_IS_HTTP_STREAMING(player))
986 data_size = player->http_content_size;
988 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
989 if (!player->streamer->is_adaptive_streaming) {
990 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
994 /* adaptivedemux2 is used for buffering in uridecodebin3 */
995 if (!player->streamer->buffering_req.is_pre_buffering) {
996 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
997 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
998 "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
1004 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1006 int ret = MM_ERROR_NONE;
1007 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1008 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1009 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1010 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1012 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1013 LOGW("do nothing for buffering msg");
1014 ret = MM_ERROR_PLAYER_INVALID_STATE;
1018 prev_state = MMPLAYER_PREV_STATE(player);
1019 current_state = MMPLAYER_CURRENT_STATE(player);
1020 target_state = MMPLAYER_TARGET_STATE(player);
1021 pending_state = MMPLAYER_PENDING_STATE(player);
1023 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1024 MMPLAYER_STATE_GET_NAME(prev_state),
1025 MMPLAYER_STATE_GET_NAME(current_state),
1026 MMPLAYER_STATE_GET_NAME(pending_state),
1027 MMPLAYER_STATE_GET_NAME(target_state),
1028 player->streamer->buffering_state);
1030 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1031 /* NOTE : if buffering has done, player has to go to target state. */
1032 switch (target_state) {
1033 case MM_PLAYER_STATE_PAUSED:
1035 switch (pending_state) {
1036 case MM_PLAYER_STATE_PLAYING:
1037 _mmplayer_gst_pause(player, TRUE);
1040 case MM_PLAYER_STATE_PAUSED:
1041 LOGD("player is already going to paused state, there is nothing to do.");
1044 case MM_PLAYER_STATE_NONE:
1045 case MM_PLAYER_STATE_NULL:
1046 case MM_PLAYER_STATE_READY:
1048 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1054 case MM_PLAYER_STATE_PLAYING:
1056 switch (pending_state) {
1057 case MM_PLAYER_STATE_NONE:
1059 if (current_state != MM_PLAYER_STATE_PLAYING)
1060 _mmplayer_gst_resume(player, TRUE);
1064 case MM_PLAYER_STATE_PAUSED:
1065 /* NOTE: It should be worked as asynchronously.
1066 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1068 if (current_state == MM_PLAYER_STATE_PLAYING) {
1069 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1070 * The current state should be changed to paused purposely to prevent state conflict.
1072 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1074 _mmplayer_gst_resume(player, TRUE);
1077 case MM_PLAYER_STATE_PLAYING:
1078 LOGD("player is already going to playing state, there is nothing to do.");
1081 case MM_PLAYER_STATE_NULL:
1082 case MM_PLAYER_STATE_READY:
1084 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1090 case MM_PLAYER_STATE_NULL:
1091 case MM_PLAYER_STATE_READY:
1092 case MM_PLAYER_STATE_NONE:
1094 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1098 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1099 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1101 switch (pending_state) {
1102 case MM_PLAYER_STATE_NONE:
1104 if (current_state != MM_PLAYER_STATE_PAUSED) {
1105 /* rtsp streaming pause makes rtsp server stop sending data. */
1106 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1107 LOGD("set pause state during buffering");
1108 _mmplayer_gst_pause(player, TRUE);
1114 case MM_PLAYER_STATE_PLAYING:
1115 /* rtsp streaming pause makes rtsp server stop sending data. */
1116 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1117 _mmplayer_gst_pause(player, TRUE);
1120 case MM_PLAYER_STATE_PAUSED:
1123 case MM_PLAYER_STATE_NULL:
1124 case MM_PLAYER_STATE_READY:
1126 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1135 static stream_variant_t *
1136 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1138 stream_variant_t *var_info = NULL;
1139 g_return_val_if_fail(self != NULL, NULL);
1141 var_info = g_new0(stream_variant_t, 1);
1142 if (!var_info) return NULL;
1143 var_info->bandwidth = self->bandwidth;
1144 var_info->width = self->width;
1145 var_info->height = self->height;
1150 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1156 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1157 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1159 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1160 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1161 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1163 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1164 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1165 player->http_content_size = (bytes > 0) ? bytes : 0;
1168 /* handling audio clip which has vbr. means duration is keep changing */
1169 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1178 __mmplayer_eos_timer_cb(gpointer u_data)
1180 mmplayer_t *player = NULL;
1181 MMHandleType attrs = 0;
1184 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1186 player = (mmplayer_t *)u_data;
1187 attrs = MMPLAYER_GET_ATTRS(player);
1189 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1193 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1194 if (ret_value != MM_ERROR_NONE)
1195 LOGE("seeking to 0 failed in repeat play");
1198 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1201 /* we are returning FALSE as we need only one posting */
1206 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1208 MMPLAYER_RETURN_IF_FAIL(player);
1210 /* post now if delay is zero */
1211 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1212 LOGD("eos delay is zero. posting EOS now");
1213 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1215 if (player->audio_decoded_cb)
1216 _mmplayer_cancel_eos_timer(player);
1221 /* cancel if existing */
1222 _mmplayer_cancel_eos_timer(player);
1224 /* init new timeout */
1225 /* NOTE : consider give high priority to this timer */
1226 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1228 player->eos_timer = g_timeout_add(delay_in_ms,
1229 __mmplayer_eos_timer_cb, player);
1231 player->context.global_default = g_main_context_default();
1232 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1234 /* check timer is valid. if not, send EOS now */
1235 if (player->eos_timer == 0) {
1236 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1237 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1242 __mmplayer_gst_pending_seek(mmplayer_t *player)
1244 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1245 int ret = MM_ERROR_NONE;
1249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1251 if (!player->pending_seek.is_pending) {
1252 LOGD("pending seek is not reserved. nothing to do.");
1256 /* check player state if player could pending seek or not. */
1257 current_state = MMPLAYER_CURRENT_STATE(player);
1259 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1260 LOGW("try to pending seek in %s state, try next time. ",
1261 MMPLAYER_STATE_GET_NAME(current_state));
1265 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1267 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1268 if (ret != MM_ERROR_NONE)
1269 LOGE("failed to seek pending position. just keep staying current position.");
1271 player->pending_seek.is_pending = false;
1279 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1281 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1283 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1285 audiobin = player->pipeline->audiobin; /* can be null */
1286 videobin = player->pipeline->videobin; /* can be null */
1287 textbin = player->pipeline->textbin; /* can be null */
1289 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1291 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1292 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1294 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1295 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1297 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1298 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1304 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1306 mmplayer_gst_element_t *textbin;
1309 MMPLAYER_RETURN_IF_FAIL(player &&
1311 player->pipeline->textbin);
1313 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1315 textbin = player->pipeline->textbin;
1318 LOGD("Drop subtitle text after getting EOS");
1320 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1321 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1323 player->is_subtitle_force_drop = TRUE;
1325 if (player->is_subtitle_force_drop == TRUE) {
1326 LOGD("Enable subtitle data path without drop");
1328 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1329 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1331 LOGD("non-connected with external display");
1333 player->is_subtitle_force_drop = FALSE;
1339 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1341 MMHandleType attrs = 0;
1346 /* NOTE : EOS event is coming multiple time. watch out it */
1347 /* check state. we only process EOS when pipeline state goes to PLAYING */
1348 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1349 LOGD("EOS received on non-playing state. ignoring it");
1353 if (player->pipeline && player->pipeline->textbin)
1354 __mmplayer_drop_subtitle(player, TRUE);
1356 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1357 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1359 /* rewind if repeat count is greater then zero */
1360 /* get play count */
1361 attrs = MMPLAYER_GET_ATTRS(player);
1363 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1365 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1367 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1368 if (player->playback_rate < 0.0) {
1369 player->resumed_by_rewind = TRUE;
1370 _mmplayer_set_mute((MMHandleType)player, false);
1371 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1374 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1377 player->sent_bos = FALSE;
1379 LOGD("do not post eos msg for repeating");
1384 if (player->pipeline)
1385 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1387 /* post eos message to application */
1388 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1390 /* reset last position */
1391 player->last_position = 0;
1398 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1400 GError *error = NULL;
1401 gchar *debug = NULL;
1405 /* generating debug info before returning error */
1406 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1408 /* get error code */
1409 gst_message_parse_error(msg, &error, &debug);
1411 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1412 /* Note : the streaming error from the streaming source is handled
1413 * using __mmplayer_handle_streaming_error.
1415 __mmplayer_handle_streaming_error(player, msg, error);
1417 /* dump state of all element */
1418 _mmplayer_dump_pipeline_state(player);
1420 /* translate gst error code to msl error code. then post it
1421 * to application if needed
1423 __mmplayer_handle_gst_error(player, msg, error);
1426 LOGE("error debug : %s", debug);
1429 MMPLAYER_FREEIF(debug);
1430 g_error_free(error);
1437 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1439 MMMessageParamType msg_param = {0, };
1440 int bRet = MM_ERROR_NONE;
1443 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1445 if (!MMPLAYER_IS_STREAMING(player)) {
1446 LOGW("this is not streaming playback.");
1450 MMPLAYER_CMD_LOCK(player);
1452 if (!player->streamer) {
1453 LOGW("Pipeline is shutting down");
1454 MMPLAYER_CMD_UNLOCK(player);
1458 /* ignore the remained buffering message till getting 100% msg */
1459 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1460 gint buffer_percent = 0;
1462 gst_message_parse_buffering(msg, &buffer_percent);
1464 if (buffer_percent == MAX_BUFFER_PERCENT) {
1465 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1466 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1467 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1469 MMPLAYER_CMD_UNLOCK(player);
1473 /* ignore the remained buffering message */
1474 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1475 gint buffer_percent = 0;
1477 gst_message_parse_buffering(msg, &buffer_percent);
1479 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1480 player->streamer->buffering_percent, buffer_percent);
1482 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1483 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1484 player->streamer->buffering_req.is_pre_buffering = FALSE;
1486 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1488 LOGD("interrupted buffering - ignored the remained buffering msg!");
1489 MMPLAYER_CMD_UNLOCK(player);
1494 __mmplayer_update_buffer_setting(player, msg);
1496 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1498 if (bRet == MM_ERROR_NONE) {
1499 msg_param.connection.buffering = player->streamer->buffering_percent;
1500 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1502 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1503 player->pending_resume &&
1504 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1506 player->is_external_subtitle_added_now = FALSE;
1507 player->pending_resume = FALSE;
1508 _mmplayer_resume((MMHandleType)player);
1511 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1512 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1514 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1515 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1516 player->seek_state = MMPLAYER_SEEK_NONE;
1517 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1518 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1519 /* Considering the async state transition in case of RTSP.
1520 After getting state change gst msg, seek completed msg will be posted. */
1521 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1525 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1526 if (!player->streamer) {
1527 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1528 MMPLAYER_CMD_UNLOCK(player);
1532 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1534 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1535 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1537 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1538 msg_param.connection.buffering = player->streamer->buffering_percent;
1539 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1541 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1544 msg_param.connection.buffering = player->streamer->buffering_percent;
1545 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1548 MMPLAYER_CMD_UNLOCK(player);
1556 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1558 mmplayer_gst_element_t *mainbin;
1559 const GValue *voldstate, *vnewstate, *vpending;
1560 GstState oldstate = GST_STATE_NULL;
1561 GstState newstate = GST_STATE_NULL;
1562 GstState pending = GST_STATE_NULL;
1565 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1567 mainbin = player->pipeline->mainbin;
1569 /* we only handle messages from pipeline */
1570 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1573 /* get state info from msg */
1574 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1575 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1576 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1578 if (!voldstate || !vnewstate) {
1579 LOGE("received msg has wrong format.");
1583 oldstate = (GstState)voldstate->data[0].v_int;
1584 newstate = (GstState)vnewstate->data[0].v_int;
1586 pending = (GstState)vpending->data[0].v_int;
1588 LOGD("state changed [%s] : %s ---> %s final : %s",
1589 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1590 gst_element_state_get_name((GstState)oldstate),
1591 gst_element_state_get_name((GstState)newstate),
1592 gst_element_state_get_name((GstState)pending));
1594 if (newstate == GST_STATE_PLAYING) {
1595 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1597 int retVal = MM_ERROR_NONE;
1598 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1600 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1602 if (MM_ERROR_NONE != retVal)
1603 LOGE("failed to seek pending position. just keep staying current position.");
1605 player->pending_seek.is_pending = false;
1609 if (oldstate == newstate) {
1610 LOGD("pipeline reports state transition to old state");
1615 case GST_STATE_PAUSED:
1617 gboolean prepare_async = FALSE;
1619 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1620 // managed prepare async case
1621 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1622 LOGD("checking prepare mode for async transition - %d", prepare_async);
1625 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1626 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1628 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1629 _mm_player_streaming_set_content_bitrate(player->streamer,
1630 player->total_maximum_bitrate, player->total_bitrate);
1632 if (player->pending_seek.is_pending) {
1633 LOGW("trying to do pending seek");
1634 MMPLAYER_CMD_LOCK(player);
1635 __mmplayer_gst_pending_seek(player);
1636 MMPLAYER_CMD_UNLOCK(player);
1642 case GST_STATE_PLAYING:
1644 if (MMPLAYER_IS_STREAMING(player)) {
1645 // managed prepare async case when buffering is completed
1646 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1647 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1648 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1649 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1651 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1653 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1654 if (player->streamer->buffering_percent < 100) {
1656 MMMessageParamType msg_param = {0, };
1657 LOGW("Posting Buffering Completed Message to Application !!!");
1659 msg_param.connection.buffering = 100;
1660 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1665 if (player->gapless.stream_changed) {
1666 _mmplayer_update_content_attrs(player, ATTR_ALL);
1667 player->gapless.stream_changed = FALSE;
1670 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1671 player->seek_state = MMPLAYER_SEEK_NONE;
1672 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1676 case GST_STATE_VOID_PENDING:
1677 case GST_STATE_NULL:
1678 case GST_STATE_READY:
1688 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1690 const gchar *structure_name;
1691 gint count = 0, idx = 0;
1694 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1696 if (gst_message_get_structure(msg) == NULL)
1699 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1700 if (!structure_name)
1703 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1705 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1706 const GValue *var_info = NULL;
1708 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1709 if (var_info != NULL) {
1710 if (player->adaptive_info.var_list)
1711 g_list_free_full(player->adaptive_info.var_list, g_free);
1713 /* share addr or copy the list */
1714 player->adaptive_info.var_list =
1715 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1717 count = g_list_length(player->adaptive_info.var_list);
1719 stream_variant_t *temp = NULL;
1721 /* print out for debug */
1722 LOGD("num of variant_info %d", count);
1723 for (idx = 0; idx < count; idx++) {
1724 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1726 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1732 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1733 gint num_buffers = 0;
1734 gint extra_num_buffers = 0;
1736 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1737 LOGD("video_num_buffers : %d", num_buffers);
1738 mm_player_set_attribute((MMHandleType)player, NULL,
1739 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1742 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1743 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1744 mm_player_set_attribute((MMHandleType)player, NULL,
1745 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1750 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1751 _mmplayer_track_update_text_attr_info(player, msg);
1753 /* custom message */
1754 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1755 MMMessageParamType msg_param = {0,};
1756 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1757 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1760 /* custom message for RTSP attribute :
1761 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1762 sdp which has contents info is received when rtsp connection is opened.
1763 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1764 if (!strcmp(structure_name, "rtspsrc_properties")) {
1765 g_autofree gchar *audio_codec = NULL;
1766 g_autofree gchar *video_codec = NULL;
1767 g_autofree gchar *video_frame_size = NULL;
1769 gst_structure_get(gst_message_get_structure(msg),
1770 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1771 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1772 player->streaming_type = _mmplayer_get_stream_service_type(player);
1774 gst_structure_get(gst_message_get_structure(msg),
1775 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1776 LOGD("rtsp_audio_codec : %s", audio_codec);
1778 mm_player_set_attribute((MMHandleType)player, NULL,
1779 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1781 gst_structure_get(gst_message_get_structure(msg),
1782 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1783 LOGD("rtsp_video_codec : %s", video_codec);
1785 mm_player_set_attribute((MMHandleType)player, NULL,
1786 "content_video_codec", video_codec, strlen(video_codec), NULL);
1788 gst_structure_get(gst_message_get_structure(msg),
1789 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1790 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1791 if (video_frame_size) {
1792 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1793 mm_player_set_attribute((MMHandleType)player, NULL,
1794 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1795 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1797 g_strfreev(res_str);
1806 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1808 mmplayer_gst_element_t *mainbin;
1811 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1813 mainbin = player->pipeline->mainbin;
1815 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1817 /* we only handle messages from pipeline */
1818 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1821 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1822 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1823 player->seek_state = MMPLAYER_SEEK_NONE;
1824 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1825 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1826 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1827 LOGD("sync %s state(%s) with parent state(%s)",
1828 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1829 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1830 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1832 /* In case of streaming, pause is required before finishing seeking by buffering.
1833 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1834 Because the buffering state is controlled according to the state transition for force resume,
1835 the decodebin state should be paused as player state. */
1836 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1839 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1840 (player->streamer) &&
1841 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1842 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1843 GstQuery *query = NULL;
1844 gboolean busy = FALSE;
1847 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1848 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1849 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1850 gst_query_parse_buffering_percent(query, &busy, &percent);
1851 gst_query_unref(query);
1853 LOGD("buffered percent(%s): %d",
1854 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1858 __mmplayer_handle_buffering_playback(player);
1861 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1871 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1873 GValue val = { 0, };
1875 guint indent = GPOINTER_TO_UINT(user_data);
1877 if (!gst_tag_list_copy_value(&val, tags, tag))
1880 if (G_VALUE_HOLDS_STRING(&val))
1881 str = g_value_dup_string(&val);
1883 str = gst_value_serialize(&val);
1885 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1887 g_value_unset(&val);
1892 __mmplayer_dump_collection(GstStreamCollection * collection)
1896 GstTagList *tags = NULL;
1898 GstCaps *caps = NULL;
1900 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1901 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1902 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1903 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1904 gst_stream_get_stream_flags(stream));
1905 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1907 caps = gst_stream_get_caps(stream);
1909 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1910 gst_caps_unref(caps);
1914 tags = gst_stream_get_tags(stream);
1917 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1918 gst_tag_list_unref(tags);
1925 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1926 GstStream *stream, GParamSpec *pspec, gpointer data)
1928 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1929 gst_stream_get_stream_id(stream), pspec->name, collection);
1930 if (g_str_equal(pspec->name, "caps")) {
1931 GstCaps *caps = gst_stream_get_caps(stream);
1932 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1933 gst_caps_unref(caps);
1937 if (g_str_equal (pspec->name, "tags")) {
1938 GstTagList *tags = gst_stream_get_tags(stream);
1941 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1942 gst_tag_list_unref(tags);
1949 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1951 mmplayer_t *player = (mmplayer_t *)(data);
1953 MMPLAYER_RETURN_IF_FAIL(player);
1954 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1956 switch (GST_MESSAGE_TYPE(msg)) {
1957 case GST_MESSAGE_UNKNOWN:
1958 LOGD("unknown message received");
1961 case GST_MESSAGE_EOS:
1962 LOGD("GST_MESSAGE_EOS received");
1963 __mmplayer_gst_handle_eos_message(player, msg);
1966 case GST_MESSAGE_ERROR:
1967 _mmplayer_set_reconfigure_state(player, FALSE);
1968 __mmplayer_gst_handle_error_message(player, msg);
1971 case GST_MESSAGE_WARNING:
1974 GError *error = NULL;
1976 gst_message_parse_warning(msg, &error, &debug);
1978 LOGD("warning : %s", error->message);
1979 LOGD("debug : %s", debug);
1981 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1983 MMPLAYER_FREEIF(debug);
1984 g_error_free(error);
1988 case GST_MESSAGE_TAG:
1990 LOGD("GST_MESSAGE_TAG");
1991 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1992 LOGW("failed to extract tags from gstmessage");
1996 case GST_MESSAGE_BUFFERING:
1997 __mmplayer_gst_handle_buffering_message(player, msg);
2000 case GST_MESSAGE_STATE_CHANGED:
2001 __mmplayer_gst_handle_state_message(player, msg);
2004 case GST_MESSAGE_CLOCK_LOST:
2006 GstClock *clock = NULL;
2007 gboolean need_new_clock = FALSE;
2009 gst_message_parse_clock_lost(msg, &clock);
2010 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2012 if (!player->videodec_linked)
2013 need_new_clock = TRUE;
2014 else if (!player->ini.use_system_clock)
2015 need_new_clock = TRUE;
2017 if (need_new_clock) {
2018 LOGD("Provide clock is TRUE, do pause->resume");
2019 _mmplayer_gst_pause(player, FALSE);
2020 _mmplayer_gst_resume(player, FALSE);
2025 case GST_MESSAGE_NEW_CLOCK:
2027 GstClock *clock = NULL;
2028 gst_message_parse_new_clock(msg, &clock);
2029 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2033 case GST_MESSAGE_ELEMENT:
2034 __mmplayer_gst_handle_element_message(player, msg);
2037 case GST_MESSAGE_DURATION_CHANGED:
2039 LOGD("GST_MESSAGE_DURATION_CHANGED");
2040 if (!__mmplayer_gst_handle_duration(player, msg))
2041 LOGW("failed to update duration");
2045 case GST_MESSAGE_ASYNC_START:
2046 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2049 case GST_MESSAGE_ASYNC_DONE:
2050 __mmplayer_gst_handle_async_done_message(player, msg);
2052 case GST_MESSAGE_STREAM_COLLECTION:
2054 GstStreamCollection *collection = NULL;
2055 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2057 gst_message_parse_stream_collection(msg, &collection);
2059 __mmplayer_dump_collection(collection);
2060 if (player->collection && player->stream_notify_id) {
2061 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2062 player->stream_notify_id = 0;
2064 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2065 if (player->collection) {
2066 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2067 (GCallback)__mmplayer_stream_notify_cb, player);
2069 gst_object_unref(collection);
2072 case GST_MESSAGE_STREAMS_SELECTED:
2074 GstStreamCollection *collection = NULL;
2075 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2077 gst_message_parse_streams_selected(msg, &collection);
2079 guint i = 0, len = 0;
2080 len = gst_message_streams_selected_get_size(msg);
2081 for (i = 0; i < len; i++) {
2082 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2083 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2084 gst_object_unref(stream);
2086 gst_object_unref (collection);
2091 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2092 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2093 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2094 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2095 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2096 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2097 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2098 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2099 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2100 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2101 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2102 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2103 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2104 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2105 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2112 /* should not call 'gst_message_unref(msg)' */
2116 static GstBusSyncReply
2117 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2119 mmplayer_t *player = (mmplayer_t *)data;
2120 GstBusSyncReply reply = GST_BUS_DROP;
2122 if (!(player->pipeline && player->pipeline->mainbin)) {
2123 LOGE("player pipeline handle is null");
2124 return GST_BUS_PASS;
2127 if (!__mmplayer_gst_check_useful_message(player, message)) {
2128 gst_message_unref(message);
2129 return GST_BUS_DROP;
2132 switch (GST_MESSAGE_TYPE(message)) {
2133 case GST_MESSAGE_TAG:
2134 __mmplayer_gst_extract_tag_from_msg(player, message);
2138 GstTagList *tags = NULL;
2140 gst_message_parse_tag(message, &tags);
2142 LOGE("TAGS received from element \"%s\".",
2143 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2145 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2146 gst_tag_list_unref(tags);
2154 case GST_MESSAGE_DURATION_CHANGED:
2155 __mmplayer_gst_handle_duration(player, message);
2157 case GST_MESSAGE_ELEMENT:
2159 const gchar *klass = NULL;
2160 klass = gst_element_factory_get_metadata
2161 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2162 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2163 reply = GST_BUS_PASS;
2166 __mmplayer_gst_handle_element_message(player, message);
2169 case GST_MESSAGE_ASYNC_DONE:
2170 /* NOTE:Don't call gst_callback directly
2171 * because previous frame can be showed even though this message is received for seek.
2174 reply = GST_BUS_PASS;
2178 if (reply == GST_BUS_DROP)
2179 gst_message_unref(message);
2185 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2187 GstElement *appsrc = element;
2188 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2189 GstBuffer *buffer = NULL;
2190 GstFlowReturn ret = GST_FLOW_OK;
2193 MMPLAYER_RETURN_IF_FAIL(element);
2194 MMPLAYER_RETURN_IF_FAIL(buf);
2196 buffer = gst_buffer_new();
2198 if (buf->offset < 0 || buf->len < 0) {
2199 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2203 if (buf->offset >= buf->len) {
2204 LOGD("call eos appsrc");
2205 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2209 if (buf->len - buf->offset < size)
2210 len = buf->len - buf->offset;
2212 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2213 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2214 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2217 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2219 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2225 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2227 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2229 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2231 buf->offset = (int)size;
2237 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2239 mmplayer_t *player = (mmplayer_t *)user_data;
2240 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2241 MMMessageParamType msg_param = {0,};
2242 guint64 current_level_bytes = 0;
2244 MMPLAYER_RETURN_IF_FAIL(player);
2246 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2247 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2248 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2249 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2251 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2255 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2257 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2259 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2260 msg_param.buffer_status.stream_type = stream_type;
2261 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2262 msg_param.buffer_status.bytes = current_level_bytes;
2264 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2268 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2270 mmplayer_t *player = (mmplayer_t *)user_data;
2271 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2272 MMMessageParamType msg_param = {0,};
2273 guint64 current_level_bytes = 0;
2275 MMPLAYER_RETURN_IF_FAIL(player);
2277 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2278 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2279 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2280 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2282 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2286 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2288 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2290 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2291 msg_param.buffer_status.stream_type = stream_type;
2292 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2293 msg_param.buffer_status.bytes = current_level_bytes;
2295 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2299 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2301 mmplayer_t *player = (mmplayer_t *)user_data;
2302 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2303 MMMessageParamType msg_param = {0,};
2305 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2307 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2308 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2309 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2310 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2312 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2316 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2318 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2319 msg_param.seek_data.stream_type = stream_type;
2320 msg_param.seek_data.offset = position;
2322 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2328 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2330 #define MAX_LEN_NAME 20
2332 gboolean ret = FALSE;
2333 GstPad *sinkpad = NULL;
2334 gchar *prefix = NULL;
2335 gchar dec_name[MAX_LEN_NAME] = {0, };
2336 main_element_id_e elem_id = MMPLAYER_M_NUM;
2338 mmplayer_gst_element_t *mainbin = NULL;
2339 GstElement *decodebin = NULL;
2340 GstCaps *dec_caps = NULL;
2344 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2346 player->pipeline->mainbin, FALSE);
2347 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2349 mainbin = player->pipeline->mainbin;
2351 case MM_PLAYER_STREAM_TYPE_AUDIO:
2353 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2355 case MM_PLAYER_STREAM_TYPE_VIDEO:
2357 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2360 LOGE("invalid type %d", type);
2364 if (mainbin[elem_id].gst) {
2365 LOGE("elem(%d) is already created", elem_id);
2369 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2371 /* create decodebin */
2372 decodebin = gst_element_factory_make("decodebin", dec_name);
2374 LOGE("failed to create %s", dec_name);
2378 /* raw pad handling signal */
2379 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2380 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2382 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2383 before looking for any elements that can handle that stream.*/
2384 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2385 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2387 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2388 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2389 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2391 /* This signal is emitted when a element is added to the bin.*/
2392 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2393 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2395 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2396 LOGE("failed to add new decodebin");
2400 dec_caps = gst_pad_query_caps(srcpad, NULL);
2403 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2405 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2406 gst_caps_unref(dec_caps);
2409 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2411 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2412 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2415 gst_object_unref(GST_OBJECT(sinkpad));
2417 gst_element_sync_state_with_parent(decodebin);
2419 mainbin[elem_id].id = elem_id;
2420 mainbin[elem_id].gst = decodebin;
2427 gst_object_unref(GST_OBJECT(sinkpad));
2430 gst_element_set_state(decodebin, GST_STATE_NULL);
2431 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2432 gst_object_unref(decodebin);
2440 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2442 #define MAX_LEN_NAME 20
2443 mmplayer_gst_element_t *mainbin = NULL;
2444 gchar *prefix = NULL;
2445 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2447 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2448 GstElement *src = NULL, *queue = NULL;
2449 GstPad *srcpad = NULL;
2452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2453 player->pipeline->mainbin, FALSE);
2455 mainbin = player->pipeline->mainbin;
2457 LOGD("type(%d) path is creating", type);
2459 case MM_PLAYER_STREAM_TYPE_AUDIO:
2461 if (mainbin[MMPLAYER_M_SRC].gst)
2462 src_id = MMPLAYER_M_2ND_SRC;
2464 src_id = MMPLAYER_M_SRC;
2465 queue_id = MMPLAYER_M_A_BUFFER;
2467 case MM_PLAYER_STREAM_TYPE_VIDEO:
2469 src_id = MMPLAYER_M_SRC;
2470 queue_id = MMPLAYER_M_V_BUFFER;
2472 case MM_PLAYER_STREAM_TYPE_TEXT:
2473 prefix = "subtitle";
2474 src_id = MMPLAYER_M_SUBSRC;
2475 queue_id = MMPLAYER_M_S_BUFFER;
2478 LOGE("invalid type %d", type);
2482 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2483 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2486 src = gst_element_factory_make("appsrc", src_name);
2488 LOGF("failed to create %s", src_name);
2492 mainbin[src_id].id = src_id;
2493 mainbin[src_id].gst = src;
2495 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2496 "caps", caps, NULL);
2498 /* size of many video frames are larger than default blocksize as 4096 */
2499 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2500 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2502 if (player->media_stream_buffer_max_size[type] > 0)
2503 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2505 if (player->media_stream_buffer_min_percent[type] > 0)
2506 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2508 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2509 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2511 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2512 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2513 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2514 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2515 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2516 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2519 queue = gst_element_factory_make("queue2", queue_name);
2521 LOGE("failed to create %s", queue_name);
2524 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2526 mainbin[queue_id].id = queue_id;
2527 mainbin[queue_id].gst = queue;
2529 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2530 LOGE("failed to add src");
2534 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2535 LOGE("failed to add queue");
2539 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2540 LOGE("failed to link src and queue");
2544 /* create decoder */
2545 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2547 LOGE("failed to get srcpad of queue");
2551 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2552 _mmplayer_gst_create_decoder(player, srcpad, caps);
2554 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2555 LOGE("failed to create decoder");
2556 gst_object_unref(GST_OBJECT(srcpad));
2560 gst_object_unref(GST_OBJECT(srcpad));
2564 if (mainbin[src_id].gst) {
2565 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2566 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2567 gst_object_unref(mainbin[src_id].gst);
2568 mainbin[src_id].gst = NULL;
2571 if (mainbin[queue_id].gst) {
2572 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2573 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2574 gst_object_unref(mainbin[queue_id].gst);
2575 mainbin[queue_id].gst = NULL;
2582 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2584 GstPad *sinkpad = NULL;
2585 GstCaps *caps = NULL;
2586 GstElement *new_element = NULL;
2587 GstStructure *str = NULL;
2588 const gchar *name = NULL;
2590 mmplayer_t *player = (mmplayer_t *)data;
2594 MMPLAYER_RETURN_IF_FAIL(element && pad);
2595 MMPLAYER_RETURN_IF_FAIL(player &&
2597 player->pipeline->mainbin);
2599 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2600 * num_dynamic_pad will decreased after creating a sinkbin.
2602 player->num_dynamic_pad++;
2603 LOGD("stream count inc : %d", player->num_dynamic_pad);
2605 caps = gst_pad_query_caps(pad, NULL);
2606 MMPLAYER_CHECK_NULL(caps);
2608 str = gst_caps_get_structure(caps, 0);
2609 name = gst_structure_get_string(str, "media");
2611 LOGE("cannot get mimetype from structure.");
2615 if (strstr(name, "video")) {
2617 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2619 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2620 if (player->v_stream_caps) {
2621 gst_caps_unref(player->v_stream_caps);
2622 player->v_stream_caps = NULL;
2625 new_element = gst_element_factory_make("fakesink", NULL);
2626 player->num_dynamic_pad--;
2631 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2632 LOGE("failed to autoplug for caps");
2636 gst_caps_unref(caps);
2641 /* execute new_element if created*/
2643 LOGD("adding new element to pipeline");
2645 /* set state to READY before add to bin */
2646 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2648 /* add new element to the pipeline */
2649 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2650 LOGE("failed to add autoplug element to bin");
2654 /* get pad from element */
2655 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2657 LOGE("failed to get sinkpad from autoplug element");
2662 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2663 LOGE("failed to link autoplug element");
2667 gst_object_unref(sinkpad);
2670 /* run. setting PLAYING here since streaming source is live source */
2671 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2675 gst_caps_unref(caps);
2681 STATE_CHANGE_FAILED:
2683 /* FIXIT : take care if new_element has already added to pipeline */
2685 gst_object_unref(GST_OBJECT(new_element));
2688 gst_object_unref(GST_OBJECT(sinkpad));
2691 gst_caps_unref(caps);
2693 /* FIXIT : how to inform this error to MSL ????? */
2694 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2695 * then post an error to application
2700 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2702 mmplayer_t *player = (mmplayer_t *)data;
2706 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2707 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2708 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2709 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2711 * [1] audio and video will be dumped with filesink.
2712 * [2] autoplugging is done by just using pad caps.
2713 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2714 * and the video will be dumped via filesink.
2716 if (player->num_dynamic_pad == 0) {
2717 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2719 if (!_mmplayer_gst_remove_fakesink(player,
2720 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2721 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2722 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2723 * source element are not same. To overcome this situation, this function will called
2724 * several places and several times. Therefore, this is not an error case.
2729 /* create dot before error-return. for debugging */
2730 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2732 player->no_more_pad = TRUE;
2738 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2740 GstElement *element = NULL;
2741 gchar *user_agent = NULL;
2742 MMHandleType attrs = 0;
2745 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2747 /* get profile attribute */
2748 attrs = MMPLAYER_GET_ATTRS(player);
2750 LOGE("failed to get content attribute");
2754 element = gst_element_factory_make("rtspsrc", "rtsp source");
2756 LOGE("failed to create rtspsrc element");
2761 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2763 SECURE_LOGD("user_agent : %s", user_agent);
2765 /* setting property to streaming source */
2766 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2768 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2770 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2771 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2772 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2773 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2779 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2781 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2783 mmplayer_t *player = (mmplayer_t *)data;
2784 MMHandleType attrs = 0;
2785 gchar *user_agent, *cookies, **cookie_list;
2786 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2787 user_agent = cookies = NULL;
2791 MMPLAYER_RETURN_IF_FAIL(player);
2793 LOGD("source element %s", GST_ELEMENT_NAME(source));
2795 attrs = MMPLAYER_GET_ATTRS(player);
2797 LOGE("failed to get content attribute");
2801 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2802 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2804 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2805 http_timeout = player->ini.http_timeout;
2807 SECURE_LOGD("cookies : %s", cookies);
2808 SECURE_LOGD("user_agent : %s", user_agent);
2809 LOGD("timeout : %d", http_timeout);
2811 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2813 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2814 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2815 g_strfreev(cookie_list);
2819 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2825 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2827 mmplayer_t *player = (mmplayer_t *)data;
2828 gchar *user_agent = NULL;
2829 MMHandleType attrs = 0;
2832 MMPLAYER_RETURN_IF_FAIL(player);
2834 attrs = MMPLAYER_GET_ATTRS(player);
2836 LOGE("failed to get content attribute");
2840 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2842 SECURE_LOGD("user_agent : %s", user_agent);
2845 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2851 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2853 mmplayer_t *player = (mmplayer_t *)data;
2854 GstElement *source = NULL;
2857 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2859 g_object_get(orig, pspec->name, &source, NULL);
2861 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2862 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2864 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2865 __mmplayer_http_src_setup(source, data);
2866 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2867 __mmplayer_rtsp_src_setup(source, data);
2868 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2869 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2870 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2871 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2872 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2874 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2875 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2876 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2877 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2879 gst_object_unref (source);
2885 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
2887 const gchar *stream1_id = gst_stream_get_stream_id((GstStream *)stream1);
2888 const gchar *stream2_id = gst_stream_get_stream_id((GstStream *)stream2);
2890 return (g_strcmp0(stream1_id, stream2_id) == 0);
2894 __mmplayer_has_duplicated_stream(mmplayer_t *player, GstStreamType stype, GstStream *stream)
2896 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2898 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2901 case GST_STREAM_TYPE_AUDIO:
2902 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2904 case GST_STREAM_TYPE_VIDEO:
2905 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2907 case GST_STREAM_TYPE_TEXT:
2908 type = MM_PLAYER_TRACK_TYPE_TEXT;
2911 LOGD("Skip not supported stream stype");
2915 return g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL);
2919 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2920 GstStream * stream, gpointer data)
2922 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2923 GstStreamType stype = gst_stream_get_stream_type(stream);
2924 mmplayer_t *player = (mmplayer_t *)data;
2925 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2926 GstCaps *caps = gst_stream_get_caps(stream);
2927 GstStructure *caps_structure = NULL;
2928 gchar *caps_str = NULL;
2930 LOGD("Stream type %s flags 0x%x",
2931 gst_stream_type_get_name(stype),
2932 gst_stream_get_stream_flags(stream));
2933 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2935 if (__mmplayer_has_duplicated_stream(player, stype, stream)) {
2936 LOGD("Already added stream, skip it");
2942 caps_str = gst_caps_to_string(caps);
2943 caps_structure = gst_caps_get_structure(caps, 0);
2944 const gchar *mime = gst_structure_get_name(caps_structure);
2946 LOGD(" caps: %s", caps_str);
2948 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2949 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2950 LOGW("skip [%s] by unsupported codec keyword [%s]",
2951 mime, player->ini.unsupported_codec_keyword[idx]);
2953 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2961 case GST_STREAM_TYPE_AUDIO:
2963 gint samplerate = 0;
2966 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2968 if (caps_structure) {
2969 gst_structure_get_int(caps_structure, "rate", &samplerate);
2970 gst_structure_get_int(caps_structure, "channels", &channels);
2972 if (channels > 0 && samplerate == 0) {
2973 LOGW("Skip corrupted audio stream");
2977 if (g_strrstr(caps_str, "mobile-xmf"))
2978 mm_player_set_attribute((MMHandleType)player, NULL,
2979 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2983 case GST_STREAM_TYPE_VIDEO:
2988 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2990 /* do not support multi track video */
2991 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2994 // FIXME: it cause block during preparing
2995 if ((!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && (!MMPLAYER_IS_DASH_STREAMING(player))) {
2996 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) {
3007 gst_structure_get_int(caps_structure, "width", &width);
3010 if (player->v_stream_caps) {
3011 gst_caps_unref(player->v_stream_caps);
3012 player->v_stream_caps = NULL;
3015 player->v_stream_caps = gst_caps_copy(caps);
3016 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3021 case GST_STREAM_TYPE_TEXT:
3022 type = MM_PLAYER_TRACK_TYPE_TEXT;
3025 LOGW("Skip not supported stream type");
3029 _mmplayer_track_update_stream(player, type, stream);
3031 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3032 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3033 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3034 _mmplayer_set_audio_attrs(player, caps);
3041 gst_caps_unref(caps);
3043 LOGD("ret %d", ret);
3048 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3049 GstStream * stream, gpointer data)
3051 mmplayer_t *player = (mmplayer_t *)data;
3052 GstStreamType stype = gst_stream_get_stream_type(stream);
3055 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3057 LOGD("stream type %s", gst_stream_type_get_name(stype));
3059 /* public does not support audio hw decoder at the moment */
3061 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3062 LOGW("video decoder resource is already acquired, skip it.");
3066 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3067 LOGE("failed to acquire video decoder resource");
3070 player->interrupted_by_resource = FALSE;
3076 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3078 GstIterator *iter = NULL;
3079 GValue item = {0, };
3080 GstElement *ch_element = NULL;
3081 GstElementFactory *ch_factory = NULL;
3084 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3086 iter = gst_bin_iterate_recurse(bin);
3087 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3089 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3090 ch_element = g_value_get_object(&item);
3091 ch_factory = gst_element_get_factory(ch_element);
3092 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3093 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3094 LOGD("Find %s element", element_name);
3098 g_value_reset(&item);
3100 gst_iterator_free(iter);
3106 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3108 mmplayer_t *player = (mmplayer_t *)data;
3110 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3112 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3113 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3114 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3116 _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3117 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3118 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3121 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3123 mmplayer_t *player = (mmplayer_t *)data;
3124 int video_codec_type = 0;
3125 int audio_codec_type = 0;
3127 g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3129 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3130 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3132 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3134 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3135 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3136 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3137 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3139 _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3140 "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3144 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3146 gchar *factory_name = NULL;
3147 mmplayer_t *player = (mmplayer_t *)data;
3150 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3152 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3154 LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3156 if (g_strrstr(factory_name, "urisourcebin")) {
3157 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3159 GstElement *mq = __mmplayer_gst_find_child_element(child, "multiqueue");
3161 g_object_set(G_OBJECT(mq), "use-interleave", FALSE, NULL);
3163 __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3165 LOGW("failed to find decodebin3");
3167 } else if (g_strrstr(factory_name, "parsebin")) {
3168 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3169 __mmplayer_parsebin_setup(GST_BIN(element), data);
3171 _mmplayer_gst_element_added(child, element, data);
3176 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3180 MMPLAYER_RETURN_IF_FAIL(player);
3181 MMPLAYER_RETURN_IF_FAIL(removed_element);
3183 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3185 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3186 GList *node = player->signals[type];
3188 GList *next_node = node->next;
3189 mmplayer_signal_item_t *item = node->data;
3190 if (item && item->obj == G_OBJECT(removed_element)) {
3191 player->signals[type] = g_list_delete_link(player->signals[type], node);
3192 MMPLAYER_FREEIF(item);
3202 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3204 mmplayer_t *player = (mmplayer_t *)data;
3208 MMPLAYER_RETURN_IF_FAIL(player);
3210 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3212 __mmplayer_delete_signal_connection(player, element);
3218 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3220 GstElement *uridecodebin3 = NULL;
3223 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3225 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3226 if (!uridecodebin3) {
3227 LOGE("failed to create uridecodebin3");
3232 SECURE_LOGD("uri : %s", player->profile.uri);
3234 /* setting property to streaming source */
3235 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3236 "message-forward", TRUE,
3237 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3238 "use-buffering", TRUE, NULL);
3240 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3241 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3243 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3244 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3246 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3247 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3249 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3250 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3252 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3253 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3255 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3256 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3258 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3259 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3261 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3262 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3264 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3265 LOGW("[DASH] this is still experimental feature");
3268 return uridecodebin3;
3272 __mmplayer_gst_make_http_src(mmplayer_t *player)
3274 #define MAX_RETRY_COUNT 10
3275 GstElement *element = NULL;
3276 MMHandleType attrs = 0;
3277 gchar *user_agent, *cookies, **cookie_list;
3278 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3280 user_agent = cookies = NULL;
3284 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3286 /* get profile attribute */
3287 attrs = MMPLAYER_GET_ATTRS(player);
3289 LOGE("failed to get content attribute");
3293 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3295 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3297 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3302 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3303 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3305 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3306 http_timeout = player->ini.http_timeout;
3309 SECURE_LOGD("location : %s", player->profile.uri);
3310 SECURE_LOGD("cookies : %s", cookies);
3311 SECURE_LOGD("user_agent : %s", user_agent);
3312 LOGD("timeout : %d", http_timeout);
3314 /* setting property to streaming source */
3315 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3316 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3317 "retries", MAX_RETRY_COUNT, NULL);
3319 /* parsing cookies */
3320 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3321 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3322 g_strfreev(cookie_list);
3326 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3328 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3329 LOGW("[DASH] this is still experimental feature");
3336 __mmplayer_gst_make_file_src(mmplayer_t *player)
3338 GstElement *element = NULL;
3341 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3343 LOGD("using filesrc for 'file://' handler");
3344 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3345 LOGE("failed to get storage info");
3349 element = gst_element_factory_make("filesrc", "source");
3351 LOGE("failed to create filesrc");
3355 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3362 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3364 mmplayer_t *player = (mmplayer_t *)data;
3366 g_return_val_if_fail(player, FALSE);
3367 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3368 gst_message_ref(msg);
3370 g_mutex_lock(&player->bus_msg_q_lock);
3371 g_queue_push_tail(player->bus_msg_q, msg);
3372 g_mutex_unlock(&player->bus_msg_q_lock);
3374 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3375 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3376 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3380 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3382 mmplayer_t *player = (mmplayer_t *)(data);
3383 GstMessage *msg = NULL;
3386 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3388 player->pipeline->mainbin &&
3389 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3392 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3394 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3395 while (!player->bus_msg_thread_exit) {
3396 g_mutex_lock(&player->bus_msg_q_lock);
3397 msg = g_queue_pop_head(player->bus_msg_q);
3398 g_mutex_unlock(&player->bus_msg_q_lock);
3400 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3403 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3404 /* handle the gst msg */
3405 __mmplayer_gst_bus_msg_callback(msg, player);
3406 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3407 gst_message_unref(msg);
3410 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3417 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3419 gint64 dur_nsec = 0;
3420 gint64 pos_nsec = 0;
3423 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3425 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3426 return MM_ERROR_NONE;
3428 /* NOTE : duration cannot be zero except live streaming.
3429 * Since some element could have some timing problem with querying duration, try again.
3431 if (player->duration == 0) {
3432 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3433 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3434 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3435 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3436 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3437 player->pending_seek.is_pending = true;
3438 player->pending_seek.pos = position;
3439 player->seek_state = MMPLAYER_SEEK_NONE;
3440 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3441 return MM_ERROR_PLAYER_NO_OP;
3443 player->seek_state = MMPLAYER_SEEK_NONE;
3444 return MM_ERROR_PLAYER_SEEK;
3447 player->duration = dur_nsec;
3450 if (player->duration > 0 && player->duration < position) {
3451 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3452 return MM_ERROR_INVALID_ARGUMENT;
3455 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3456 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3457 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3458 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3459 player->seek_state = MMPLAYER_SEEK_NONE;
3460 return MM_ERROR_PLAYER_NO_OP;
3465 return MM_ERROR_NONE;
3469 __mmplayer_gst_check_seekable(mmplayer_t *player)
3471 GstQuery *query = NULL;
3472 gboolean seekable = FALSE;
3474 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3478 query = gst_query_new_seeking(GST_FORMAT_TIME);
3479 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3480 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3481 gst_query_unref(query);
3484 LOGW("non-seekable content");
3485 player->seek_state = MMPLAYER_SEEK_NONE;
3489 LOGW("failed to get seeking query");
3490 gst_query_unref(query); /* keep seeking operation */
3497 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3499 GstState element_state = GST_STATE_VOID_PENDING;
3500 GstState element_pending_state = GST_STATE_VOID_PENDING;
3501 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3505 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3506 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3508 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3511 ret = gst_element_set_state(element, state);
3512 if (ret == GST_STATE_CHANGE_FAILURE) {
3513 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3515 /* dump state of all element */
3516 _mmplayer_dump_pipeline_state(player);
3518 return MM_ERROR_PLAYER_INTERNAL;
3521 /* return here so state transition to be done in async mode */
3523 LOGD("async state transition. not waiting for state complete.");
3524 return MM_ERROR_NONE;
3527 /* wait for state transition */
3528 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3529 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3530 LOGE("failed to change [%s] element state to [%s] within %d sec",
3531 GST_ELEMENT_NAME(element),
3532 gst_element_state_get_name(state), timeout);
3534 LOGE(" [%s] state : %s pending : %s",
3535 GST_ELEMENT_NAME(element),
3536 gst_element_state_get_name(element_state),
3537 gst_element_state_get_name(element_pending_state));
3539 /* dump state of all element */
3540 _mmplayer_dump_pipeline_state(player);
3542 return MM_ERROR_PLAYER_INTERNAL;
3545 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3549 return MM_ERROR_NONE;
3553 _mmplayer_gst_start(mmplayer_t *player)
3555 int ret = MM_ERROR_NONE;
3556 gboolean async = FALSE;
3560 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3562 /* NOTE : if SetPosition was called before Start. do it now
3563 * streaming doesn't support it. so it should be always sync
3564 * !!create one more api to check if there is pending seek rather than checking variables
3566 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3567 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3568 ret = _mmplayer_gst_pause(player, FALSE);
3569 if (ret != MM_ERROR_NONE) {
3570 LOGE("failed to set state to PAUSED for pending seek");
3574 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3575 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3576 LOGW("failed to seek pending position. starting from the begin of content");
3579 LOGD("current state before doing transition");
3580 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3581 MMPLAYER_PRINT_STATE(player);
3583 /* set pipeline state to PLAYING */
3584 ret = _mmplayer_gst_set_state(player,
3585 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3586 if (ret != MM_ERROR_NONE) {
3587 LOGE("failed to set state to PLAYING");
3591 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3593 /* generating debug info before returning error */
3594 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3602 _mmplayer_gst_stop(mmplayer_t *player)
3604 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3605 MMHandleType attrs = 0;
3606 gboolean rewind = FALSE;
3608 int ret = MM_ERROR_NONE;
3612 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3613 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3615 LOGD("current state before doing transition");
3616 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3617 MMPLAYER_PRINT_STATE(player);
3619 attrs = MMPLAYER_GET_ATTRS(player);
3621 LOGE("cannot get content attribute");
3622 return MM_ERROR_PLAYER_INTERNAL;
3625 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3626 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3628 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3629 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3632 if (player->es_player_push_mode)
3633 /* disable the async state transition because there could be no data in the pipeline */
3634 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3637 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3639 if (player->es_player_push_mode) {
3640 /* enable the async state transition as default operation */
3641 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3644 /* return if set_state has failed */
3645 if (ret != MM_ERROR_NONE) {
3646 LOGE("failed to set state.");
3652 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3653 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3654 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3655 LOGW("failed to rewind");
3656 ret = MM_ERROR_PLAYER_SEEK;
3661 player->sent_bos = FALSE;
3663 if (player->es_player_push_mode) //for cloudgame
3666 /* wait for seek to complete */
3667 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3668 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3669 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3671 LOGE("fail to stop player.");
3672 ret = MM_ERROR_PLAYER_INTERNAL;
3673 _mmplayer_dump_pipeline_state(player);
3676 /* generate dot file if enabled */
3677 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3685 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3687 int ret = MM_ERROR_NONE;
3691 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3692 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3694 LOGD("current state before doing transition");
3695 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3696 MMPLAYER_PRINT_STATE(player);
3698 /* set pipeline status to PAUSED */
3699 ret = _mmplayer_gst_set_state(player,
3700 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3705 if (ret != MM_ERROR_NONE) {
3706 GstMessage *msg = NULL;
3707 GTimer *timer = NULL;
3708 gdouble MAX_TIMEOUT_SEC = 3;
3710 LOGE("failed to set state to PAUSED");
3712 if (!player->bus_watcher) {
3713 LOGE("there is no bus msg thread. pipeline is shutting down.");
3717 if (player->msg_posted) {
3718 LOGE("error msg is already posted.");
3722 timer = g_timer_new();
3723 g_timer_start(timer);
3725 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3728 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3730 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3731 GError *error = NULL;
3733 /* parse error code */
3734 gst_message_parse_error(msg, &error, NULL);
3736 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3737 /* Note : the streaming error from the streaming source is handled
3738 * using __mmplayer_handle_streaming_error.
3740 __mmplayer_handle_streaming_error(player, msg, error);
3743 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3745 if (error->domain == GST_STREAM_ERROR)
3746 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3747 else if (error->domain == GST_RESOURCE_ERROR)
3748 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3749 else if (error->domain == GST_LIBRARY_ERROR)
3750 ret = __mmplayer_gst_handle_library_error(player, error->code);
3751 else if (error->domain == GST_CORE_ERROR)
3752 ret = __mmplayer_gst_handle_core_error(player, error->code);
3754 g_error_free(error);
3756 player->msg_posted = TRUE;
3758 gst_message_unref(msg);
3760 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3762 gst_object_unref(bus);
3763 g_timer_stop(timer);
3764 g_timer_destroy(timer);
3769 if (MMPLAYER_USE_DECODEBIN(player)) {
3770 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3771 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3772 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3775 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3778 /* generate dot file before returning error */
3779 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3787 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3789 int ret = MM_ERROR_NONE;
3794 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3795 MM_ERROR_PLAYER_NOT_INITIALIZED);
3797 LOGD("current state before doing transition");
3798 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3799 MMPLAYER_PRINT_STATE(player);
3802 LOGD("do async state transition to PLAYING");
3804 /* set pipeline state to PLAYING */
3805 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3807 ret = _mmplayer_gst_set_state(player,
3808 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3809 if (ret != MM_ERROR_NONE) {
3810 LOGE("failed to set state to PLAYING");
3815 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3818 /* generate dot file */
3819 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3826 /* sending event to one of sinkelements */
3828 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3830 GstEvent *event2 = NULL;
3831 GList *sinks = NULL;
3832 gboolean res = FALSE;
3835 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3836 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3838 /* While adding subtitles in live feeds seek is getting called.
3839 Adding defensive check in framework layer.*/
3840 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3841 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3842 LOGE("Should not send seek event during live playback");
3847 if (player->play_subtitle)
3848 event2 = gst_event_copy((const GstEvent *)event);
3850 sinks = player->sink_elements;
3852 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3854 if (GST_IS_ELEMENT(sink)) {
3855 /* keep ref to the event */
3856 gst_event_ref(event);
3858 if ((res = gst_element_send_event(sink, event))) {
3859 LOGD("sending event[%s] to sink element [%s] success!",
3860 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3862 /* rtsp case, async_done is not called after seek during pause state */
3863 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3864 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3865 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3866 LOGD("RTSP seek completed, after pause state..");
3867 player->seek_state = MMPLAYER_SEEK_NONE;
3868 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3874 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3875 sinks = g_list_next(sinks);
3882 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3883 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3886 sinks = g_list_next(sinks);
3889 /* Note : Textbin is not linked to the video or audio bin.
3890 * It needs to send the event to the text sink separately.
3892 if (player->play_subtitle && player->pipeline) {
3893 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3895 if (GST_IS_ELEMENT(text_sink)) {
3896 /* keep ref to the event */
3897 gst_event_ref(event2);
3899 if ((res = gst_element_send_event(text_sink, event2)))
3900 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3901 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3903 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3904 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3906 gst_event_unref(event2);
3910 gst_event_unref(event);
3918 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3919 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3920 gint64 cur, GstSeekType stop_type, gint64 stop)
3922 GstEvent *event = NULL;
3923 gboolean result = FALSE;
3927 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3929 if (player->pipeline && player->pipeline->textbin)
3930 __mmplayer_drop_subtitle(player, FALSE);
3932 event = gst_event_new_seek(rate, format, flags, cur_type,
3933 cur, stop_type, stop);
3935 result = _mmplayer_gst_send_event_to_sink(player, event);
3943 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3945 int ret = MM_ERROR_NONE;
3946 gint64 pos_nsec = 0;
3947 gboolean accurate = FALSE;
3948 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3951 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3952 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3954 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3955 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3958 ret = __mmplayer_gst_check_position(player, position);
3959 if (ret != MM_ERROR_NONE) {
3960 LOGW("result of check position info 0x%X", ret);
3961 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3964 if (!__mmplayer_gst_check_seekable(player))
3965 return MM_ERROR_PLAYER_NO_OP;
3967 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3968 position, player->playback_rate, player->duration);
3970 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3971 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3972 This causes problem is position calculation during normal pause resume scenarios also.
3973 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3974 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3975 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3976 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3977 LOGW("getting current position failed in seek");
3979 player->last_position = pos_nsec;
3980 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3983 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3984 LOGD("not completed seek");
3985 return MM_ERROR_PLAYER_DOING_SEEK;
3988 if (!internal_called)
3989 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3991 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3992 that's why set position through property. */
3993 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3994 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3995 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3996 (!player->videodec_linked) && (!player->audiodec_linked)) {
3998 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3999 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
4001 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
4002 player->seek_state = MMPLAYER_SEEK_NONE;
4003 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4005 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4007 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4009 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4011 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4012 GST_FORMAT_TIME, seek_flags,
4013 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4014 LOGE("failed to set position");
4019 /* NOTE : store last seeking point to overcome some bad operation
4020 * (returning zero when getting current position) of some elements
4022 player->last_position = position;
4024 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4025 if (player->playback_rate > 1.0)
4026 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4028 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4029 LOGD("buffering should be reset after seeking");
4030 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4031 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4035 return MM_ERROR_NONE;
4038 player->pending_seek.is_pending = true;
4039 player->pending_seek.pos = position;
4041 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4042 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4043 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4044 player->pending_seek.pos);
4046 return MM_ERROR_NONE;
4049 player->seek_state = MMPLAYER_SEEK_NONE;
4050 return MM_ERROR_PLAYER_SEEK;
4054 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4056 #define TRICKPLAY_OFFSET GST_MSECOND
4058 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4059 gint64 pos_nsec = 0;
4060 gboolean ret = TRUE;
4062 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4063 MM_ERROR_PLAYER_NOT_INITIALIZED);
4065 current_state = MMPLAYER_CURRENT_STATE(player);
4067 /* NOTE : query position except paused state to overcome some bad operation
4068 * please refer to below comments in details
4070 if (current_state != MM_PLAYER_STATE_PAUSED)
4071 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4073 /* NOTE : get last point to overcome some bad operation of some elements
4074 *(returning zero when getting current position in paused state
4075 * and when failed to get position during seeking
4077 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4078 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4080 if (player->playback_rate < 0.0)
4081 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4083 pos_nsec = player->last_position;
4086 pos_nsec = player->last_position;
4088 player->last_position = pos_nsec;
4090 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4093 if (player->duration > 0 && pos_nsec > player->duration)
4094 pos_nsec = player->duration;
4096 player->last_position = pos_nsec;
4099 *position = pos_nsec;
4101 return MM_ERROR_NONE;
4105 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4107 #define STREAMING_IS_FINISHED 0
4108 #define BUFFERING_MAX_PER 100
4109 #define DEFAULT_PER_VALUE -1
4110 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4112 mmplayer_gst_element_t *mainbin = NULL;
4113 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4114 gint64 buffered_total = 0;
4115 gint64 position = 0;
4116 gint buffered_sec = -1;
4117 GstBufferingMode mode = GST_BUFFERING_STREAM;
4118 gint64 content_size_time = player->duration;
4119 guint64 content_size_bytes = player->http_content_size;
4121 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4123 player->pipeline->mainbin,
4124 MM_ERROR_PLAYER_NOT_INITIALIZED);
4126 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4131 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4132 /* and rtsp is not ready yet. */
4133 LOGW("it's only used for http streaming case");
4134 return MM_ERROR_PLAYER_NO_OP;
4137 if (content_size_time <= 0 || content_size_bytes <= 0) {
4138 LOGW("there is no content size");
4139 return MM_ERROR_NONE;
4142 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4143 LOGW("fail to get current position");
4144 return MM_ERROR_NONE;
4147 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4148 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4150 mainbin = player->pipeline->mainbin;
4151 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4153 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4154 GstQuery *query = NULL;
4155 gint byte_in_rate = 0, byte_out_rate = 0;
4156 gint64 estimated_total = 0;
4158 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4159 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4160 LOGW("fail to get buffering query from queue2");
4162 gst_query_unref(query);
4163 return MM_ERROR_NONE;
4166 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4167 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4169 if (mode == GST_BUFFERING_STREAM) {
4170 /* using only queue in case of push mode(ts / mp3) */
4171 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4172 GST_FORMAT_BYTES, &buffered_total)) {
4173 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4174 end_per = 100 * buffered_total / content_size_bytes;
4177 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4179 guint num_of_ranges = 0;
4180 gint64 start_byte = 0, stop_byte = 0;
4182 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4183 if (estimated_total != STREAMING_IS_FINISHED) {
4184 /* buffered size info from queue2 */
4185 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4186 for (idx = 0; idx < num_of_ranges; idx++) {
4187 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4188 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4190 buffered_total += (stop_byte - start_byte);
4193 end_per = BUFFERING_MAX_PER;
4196 gst_query_unref(query);
4199 if (end_per == DEFAULT_PER_VALUE) {
4200 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4202 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4204 /* buffered size info from multiqueue */
4205 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4206 guint curr_size_bytes = 0;
4207 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4208 "curr-size-bytes", &curr_size_bytes, NULL);
4209 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4210 buffered_total += curr_size_bytes;
4213 if (avg_byterate > 0)
4214 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4215 else if (player->total_maximum_bitrate > 0)
4216 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4217 else if (player->total_bitrate > 0)
4218 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4220 if (buffered_sec >= 0)
4221 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4225 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4226 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4228 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4229 buffered_total, buffered_sec, *start_pos, *end_pos);
4231 return MM_ERROR_NONE;
4235 _mmplayer_gst_create_source(mmplayer_t *player)
4237 GstElement *element = NULL;
4240 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4241 player->pipeline->mainbin, NULL);
4243 /* setup source for gapless play */
4244 switch (player->profile.uri_type) {
4246 case MM_PLAYER_URI_TYPE_FILE:
4247 element = __mmplayer_gst_make_file_src(player);
4249 case MM_PLAYER_URI_TYPE_URL_HTTP:
4250 element = __mmplayer_gst_make_http_src(player);
4253 LOGE("not support uri type %d", player->profile.uri_type);
4258 LOGE("failed to create source element");
4267 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4270 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4271 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4273 SECURE_LOGD("uri : %s", player->profile.uri);
4275 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4277 if ((player->v_stream_caps) &&
4278 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4279 return MM_ERROR_PLAYER_INTERNAL;
4281 if ((player->a_stream_caps) &&
4282 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4283 return MM_ERROR_PLAYER_INTERNAL;
4285 if ((player->s_stream_caps) &&
4286 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4287 return MM_ERROR_PLAYER_INTERNAL;
4290 return MM_ERROR_NONE;
4294 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4296 mmplayer_gst_element_t *mainbin = NULL;
4297 GstElement *autoplug_elem = NULL;
4300 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4301 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4303 mainbin = player->pipeline->mainbin;
4305 LOGD("uri type %d", player->profile.uri_type);
4307 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4308 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4309 return MM_ERROR_PLAYER_INTERNAL;
4312 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4313 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4316 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4317 if (!autoplug_elem) {
4318 LOGE("failed to create uridecodebin3 element");
4322 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4323 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4324 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4326 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4327 LOGE("failed to add uridecodebin to pipeline");
4331 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4332 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4333 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4335 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4336 LOGE("failed to create fakesink");
4339 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4341 /* take ownership of fakesink. we are reusing it */
4342 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4344 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4345 LOGE("failed to add fakesink to bin");
4346 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4351 return MM_ERROR_NONE;
4355 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4356 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4358 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4359 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4361 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4362 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4364 return MM_ERROR_PLAYER_INTERNAL;
4368 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4370 mmplayer_gst_element_t *mainbin = NULL;
4371 GstElement *src_elem = NULL;
4372 GstElement *autoplug_elem = NULL;
4373 GList *element_bucket = NULL;
4374 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4377 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4378 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4380 LOGD("uri type %d", player->profile.uri_type);
4382 /* create source element */
4383 switch (player->profile.uri_type) {
4384 case MM_PLAYER_URI_TYPE_URL_RTSP:
4385 src_elem = __mmplayer_gst_make_rtsp_src(player);
4387 case MM_PLAYER_URI_TYPE_URL_HTTP:
4388 src_elem = __mmplayer_gst_make_http_src(player);
4390 case MM_PLAYER_URI_TYPE_FILE:
4391 src_elem = __mmplayer_gst_make_file_src(player);
4393 case MM_PLAYER_URI_TYPE_SS:
4395 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4396 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4398 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4402 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4403 LOGD("get timeout from ini");
4404 http_timeout = player->ini.http_timeout;
4407 /* setting property to streaming source */
4408 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4411 case MM_PLAYER_URI_TYPE_MEM:
4413 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4415 src_elem = gst_element_factory_make("appsrc", "mem-source");
4417 LOGE("failed to create appsrc element");
4421 g_object_set(src_elem, "stream-type", stream_type,
4422 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4424 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4425 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4426 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4427 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4431 LOGE("not support uri type");
4436 LOGE("failed to create source element");
4437 return MM_ERROR_PLAYER_INTERNAL;
4440 mainbin = player->pipeline->mainbin;
4442 /* take source element */
4443 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4445 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4446 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4447 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4449 /* create next element for auto-plugging */
4450 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4451 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4452 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4453 if (!autoplug_elem) {
4454 LOGE("failed to create typefind element");
4458 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4459 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4460 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4461 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4462 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4463 if (!autoplug_elem) {
4464 LOGE("failed to create decodebin");
4468 /* default size of mq in decodebin is 2M
4469 * but it can cause blocking issue during seeking depends on content. */
4470 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4473 if (autoplug_elem) {
4474 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4475 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4476 mainbin[autoplug_elem_id].gst = autoplug_elem;
4478 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4481 /* add elements to pipeline */
4482 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4483 LOGE("failed to add elements to pipeline");
4487 /* linking elements in the bucket by added order. */
4488 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4489 LOGE("failed to link some elements");
4493 /* FIXME: need to check whether this is required or not. */
4494 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4495 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4496 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4497 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4498 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4500 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4501 LOGE("failed to create fakesink");
4504 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4506 /* take ownership of fakesink. we are reusing it */
4507 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4509 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4510 LOGE("failed to add fakesink to bin");
4511 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4516 g_list_free(element_bucket);
4519 return MM_ERROR_NONE;
4522 g_list_free(element_bucket);
4524 if (mainbin[MMPLAYER_M_SRC].gst)
4525 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4527 if (mainbin[autoplug_elem_id].gst)
4528 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4530 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4531 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4533 mainbin[MMPLAYER_M_SRC].gst = NULL;
4534 mainbin[autoplug_elem_id].gst = NULL;
4535 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4537 return MM_ERROR_PLAYER_INTERNAL;
4541 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4544 mmplayer_gst_element_t *mainbin = NULL;
4547 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4548 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4550 mainbin = player->pipeline->mainbin;
4552 /* connect bus callback */
4553 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4555 LOGE("cannot get bus from pipeline");
4556 return MM_ERROR_PLAYER_INTERNAL;
4559 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4560 (GstBusFunc)__mmplayer_gst_msg_push, player,
4561 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4562 if (player->bus_watcher == 0) {
4563 LOGE("failed to add bus watch");
4564 return MM_ERROR_PLAYER_INTERNAL;
4567 g_mutex_init(&player->bus_watcher_mutex);
4568 g_cond_init(&player->bus_watcher_cond);
4570 player->context.thread_default = g_main_context_get_thread_default();
4571 if (player->context.thread_default == NULL) {
4572 player->context.thread_default = g_main_context_default();
4573 LOGD("thread-default context is the global default context");
4575 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4577 /* set sync handler to get tag synchronously */
4578 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4579 gst_object_unref(GST_OBJECT(bus));
4581 /* create gst bus_msb_cb thread */
4582 g_mutex_init(&player->bus_msg_thread_mutex);
4583 g_cond_init(&player->bus_msg_thread_cond);
4584 player->bus_msg_thread_exit = FALSE;
4585 player->bus_msg_thread =
4586 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4587 if (!player->bus_msg_thread) {
4588 LOGE("failed to create gst BUS msg thread");
4589 g_mutex_clear(&player->bus_msg_thread_mutex);
4590 g_cond_clear(&player->bus_msg_thread_cond);
4591 return MM_ERROR_PLAYER_INTERNAL;
4595 return MM_ERROR_NONE;
4599 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4601 int ret = MM_ERROR_NONE;
4602 mmplayer_gst_element_t *mainbin = NULL;
4603 MMMessageParamType msg_param = {0,};
4604 GstElement *element = NULL;
4605 MMHandleType attrs = 0;
4607 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4611 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4612 LOGE("player is not initialized");
4616 mainbin = player->pipeline->mainbin;
4617 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4619 attrs = MMPLAYER_GET_ATTRS(player);
4621 LOGE("fail to get attributes");
4625 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4627 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4628 LOGE("failed to parse profile");
4629 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4633 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4634 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4635 LOGE("dash or hls is not supportable");
4636 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4640 if (!MMPLAYER_USE_DECODEBIN(player)) {
4641 ret = _mmplayer_gst_build_pipeline_with_src(player);
4642 if (ret != MM_ERROR_NONE)
4645 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4646 LOGE("Failed to change state of uridecodebin3 element");
4652 element = _mmplayer_gst_create_source(player);
4654 LOGE("no source element was created");
4658 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4659 LOGE("failed to add source element to pipeline");
4660 gst_object_unref(GST_OBJECT(element));
4665 /* take source element */
4666 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4667 mainbin[MMPLAYER_M_SRC].gst = element;
4671 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4672 if (player->streamer == NULL) {
4673 player->streamer = _mm_player_streaming_create();
4674 _mm_player_streaming_initialize(player->streamer, TRUE);
4677 elem_idx = MMPLAYER_M_TYPEFIND;
4678 element = gst_element_factory_make("typefind", "typefinder");
4679 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4680 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4682 elem_idx = MMPLAYER_M_AUTOPLUG;
4683 element = _mmplayer_gst_make_decodebin(player);
4686 /* check autoplug element is OK */
4688 LOGE("can not create element(%d)", elem_idx);
4692 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4693 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4694 gst_object_unref(GST_OBJECT(element));
4699 mainbin[elem_idx].id = elem_idx;
4700 mainbin[elem_idx].gst = element;
4702 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4703 LOGE("Failed to link src - autoplug(or typefind)");
4707 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4708 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4709 LOGE("Failed to change state of src element");
4713 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4714 LOGE("Failed to change state of decodebin");
4719 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4720 LOGE("Failed to change state of src element");
4725 player->gapless.stream_changed = TRUE;
4726 player->gapless.running = TRUE;
4732 _mmplayer_set_reconfigure_state(player, FALSE);
4733 if (!player->msg_posted) {
4734 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4735 player->msg_posted = TRUE;