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 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
60 count = gst_tag_list_get_tag_size(list, tag);
62 LOGD("count = %d", count);
64 for (i = 0; i < count; i++) {
67 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
68 if (!gst_tag_list_get_string_index(list, tag, i, &str))
69 g_assert_not_reached();
71 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
75 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
77 g_print(" : %s", str);
85 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
87 /* check whether the error is posted from not-activated track or not */
89 gint active_index = 0;
91 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
93 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
94 LOGD("current active pad index -%d", active_index);
96 if (src_element_name) {
99 if (player->audio_decoders) {
100 GList *adec = player->audio_decoders;
101 for (; adec ; adec = g_list_next(adec)) {
102 gchar *name = adec->data;
104 LOGD("found audio decoder name = %s", name);
105 if (g_strrstr(name, src_element_name)) {
112 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
115 if (active_index != msg_src_pos) {
116 LOGD("skip error because error is posted from no activated track");
124 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
126 /* Demuxer can't parse one track because it's corrupted.
127 * So, the decoder for it is not linked.
128 * But, it has one playable track.
130 if (g_strrstr(klass, "Demux")) {
131 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
132 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
133 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
134 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
136 if (player->pipeline->audiobin) { // PCM
137 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
139 LOGD("not found any available codec. Player should be destroyed.");
140 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
145 return MM_ERROR_PLAYER_INVALID_STREAM;
149 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
151 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
152 LOGE("Not supported subtitle.");
153 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
159 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
161 /* Decoder Custom Message */
162 if (!strstr(error->message, "ongoing"))
163 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
165 if (strncasecmp(klass, "audio", 5)) {
166 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
167 LOGD("Video can keep playing.");
168 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
170 } else if (strncasecmp(klass, "video", 5)) {
171 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
172 LOGD("Audio can keep playing.");
173 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
177 LOGD("not found any available codec. Player should be destroyed.");
178 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
182 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
184 if (strstr(error->message, "rights expired"))
185 return MM_ERROR_PLAYER_DRM_EXPIRED;
186 else if (strstr(error->message, "no rights"))
187 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
188 else if (strstr(error->message, "has future rights"))
189 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
190 else if (strstr(error->message, "opl violation"))
191 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
193 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
196 /* NOTE : decide gstreamer state whether there is some playable track or not. */
198 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
200 gchar *src_element_name = NULL;
201 GstElement *src_element = NULL;
202 GstElementFactory *factory = NULL;
203 const gchar *klass = NULL;
207 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
208 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
209 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
212 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
214 src_element = GST_ELEMENT_CAST(message->src);
215 src_element_name = GST_ELEMENT_NAME(src_element);
216 if (!src_element_name)
217 return MM_ERROR_PLAYER_INTERNAL;
219 factory = gst_element_get_factory(src_element);
221 return MM_ERROR_PLAYER_INTERNAL;
223 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
225 return MM_ERROR_PLAYER_INTERNAL;
227 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
228 error->code, error->message, src_element_name, klass);
230 if (MMPLAYER_USE_DECODEBIN(player) &&
231 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
232 return MM_ERROR_NONE;
234 switch (error->code) {
235 case GST_STREAM_ERROR_DECODE:
236 return __mmplayer_gst_transform_error_decode(player, klass);
237 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
238 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
239 case GST_STREAM_ERROR_WRONG_TYPE:
240 return __mmplayer_gst_transform_error_type(player, src_element);
241 case GST_STREAM_ERROR_FAILED:
242 return __mmplayer_gst_transform_error_failed(player, klass, error);
243 case GST_STREAM_ERROR_DECRYPT:
244 case GST_STREAM_ERROR_DECRYPT_NOKEY:
245 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
246 return __mmplayer_gst_transform_error_decrypt(player, error);
253 return MM_ERROR_PLAYER_INVALID_STREAM;
257 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
259 gint trans_err = MM_ERROR_NONE;
263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
266 case GST_CORE_ERROR_MISSING_PLUGIN:
267 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
268 case GST_CORE_ERROR_STATE_CHANGE:
269 case GST_CORE_ERROR_SEEK:
270 case GST_CORE_ERROR_NOT_IMPLEMENTED:
271 case GST_CORE_ERROR_FAILED:
272 case GST_CORE_ERROR_TOO_LAZY:
273 case GST_CORE_ERROR_PAD:
274 case GST_CORE_ERROR_THREAD:
275 case GST_CORE_ERROR_NEGOTIATION:
276 case GST_CORE_ERROR_EVENT:
277 case GST_CORE_ERROR_CAPS:
278 case GST_CORE_ERROR_TAG:
279 case GST_CORE_ERROR_CLOCK:
280 case GST_CORE_ERROR_DISABLED:
282 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
292 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
294 gint trans_err = MM_ERROR_NONE;
298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
301 case GST_LIBRARY_ERROR_FAILED:
302 case GST_LIBRARY_ERROR_TOO_LAZY:
303 case GST_LIBRARY_ERROR_INIT:
304 case GST_LIBRARY_ERROR_SHUTDOWN:
305 case GST_LIBRARY_ERROR_SETTINGS:
306 case GST_LIBRARY_ERROR_ENCODE:
308 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
318 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
320 gint trans_err = MM_ERROR_NONE;
324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
327 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
328 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
330 case GST_RESOURCE_ERROR_NOT_FOUND:
331 case GST_RESOURCE_ERROR_OPEN_READ:
332 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
333 || MMPLAYER_IS_RTSP_STREAMING(player)) {
334 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
337 case GST_RESOURCE_ERROR_READ:
338 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
339 || MMPLAYER_IS_RTSP_STREAMING(player)) {
340 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
342 } else if (message != NULL && message->src != NULL) {
343 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
344 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
346 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
347 path_type = MMPLAYER_PATH_VOD;
348 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
349 path_type = MMPLAYER_PATH_TEXT;
351 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
352 /* check storage state */
353 storage_get_state(player->storage_info[path_type].id, &storage_state);
354 player->storage_info[path_type].state = storage_state;
355 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
358 case GST_RESOURCE_ERROR_WRITE:
359 case GST_RESOURCE_ERROR_FAILED:
360 case GST_RESOURCE_ERROR_SEEK:
361 case GST_RESOURCE_ERROR_TOO_LAZY:
362 case GST_RESOURCE_ERROR_BUSY:
363 case GST_RESOURCE_ERROR_OPEN_WRITE:
364 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
365 case GST_RESOURCE_ERROR_CLOSE:
366 case GST_RESOURCE_ERROR_SYNC:
367 case GST_RESOURCE_ERROR_SETTINGS:
369 trans_err = MM_ERROR_PLAYER_INTERNAL;
379 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
381 gint trans_err = MM_ERROR_NONE;
385 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
386 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
387 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
389 switch (error->code) {
390 case GST_STREAM_ERROR_FAILED:
391 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
392 case GST_STREAM_ERROR_DECODE:
393 case GST_STREAM_ERROR_WRONG_TYPE:
394 case GST_STREAM_ERROR_DECRYPT:
395 case GST_STREAM_ERROR_DECRYPT_NOKEY:
396 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
397 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
400 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
401 case GST_STREAM_ERROR_TOO_LAZY:
402 case GST_STREAM_ERROR_ENCODE:
403 case GST_STREAM_ERROR_DEMUX:
404 case GST_STREAM_ERROR_MUX:
405 case GST_STREAM_ERROR_FORMAT:
407 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
417 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
419 MMMessageParamType msg_param;
420 gchar *msg_src_element;
424 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
425 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
427 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
429 memset(&msg_param, 0, sizeof(MMMessageParamType));
431 if (error->domain == GST_CORE_ERROR) {
432 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
433 } else if (error->domain == GST_LIBRARY_ERROR) {
434 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
435 } else if (error->domain == GST_RESOURCE_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
437 } else if (error->domain == GST_STREAM_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
440 LOGW("This error domain is not defined.");
442 /* we treat system error as an internal error */
443 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
447 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
449 msg_param.data = (void *)error->message;
451 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
452 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
456 if (msg_param.code == MM_ERROR_NONE)
459 /* skip error to avoid duplicated posting */
460 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
461 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
462 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
463 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
465 /* The error will be handled by mused.
466 * @ref _mmplayer_manage_external_storage_state() */
468 LOGW("storage is removed, skip error post");
472 /* post error to application */
473 if (!player->msg_posted) {
474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
475 /* don't post more if one was sent already */
476 player->msg_posted = TRUE;
478 LOGD("skip error post because it's sent already.");
487 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message, GError *error)
490 MMMessageParamType msg_param = {0, };
491 gchar *msg_src_element = NULL;
495 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
496 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
497 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
499 switch (error->code) {
500 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
501 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
503 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
504 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
506 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
507 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
509 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
510 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
512 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
513 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
515 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
516 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
518 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
519 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
521 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
522 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
524 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
525 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
527 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
528 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
530 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
531 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
533 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
534 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
536 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
537 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
539 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
540 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
542 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
543 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
545 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
546 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
548 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
549 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
551 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
552 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
554 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
555 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
557 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
558 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
560 case MMPLAYER_STREAMING_ERROR_GONE:
561 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
563 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
564 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
566 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
567 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
569 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
570 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
572 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
573 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
575 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
576 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
578 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
579 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
581 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
582 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
584 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
585 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
587 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
588 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
590 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
591 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
593 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
594 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
596 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
597 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
599 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
600 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
602 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
603 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
605 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
606 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
608 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
609 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
611 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
612 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
614 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
615 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
617 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
618 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
620 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
621 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
623 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
624 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
626 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
627 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
629 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
630 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
632 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
633 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
637 return MM_ERROR_PLAYER_STREAMING_FAIL;
642 msg_param.data = (void *)(error->message);
645 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
647 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
648 msg_src_element, msg_param.code, (char *)msg_param.data);
651 /* post error to application */
652 if (!player->msg_posted) {
653 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
655 /* don't post more if one was sent already */
656 player->msg_posted = TRUE;
658 LOGD("skip error post because it's sent already.");
667 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
669 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
670 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
671 gst_tag_list_get_string(tags, "stitching_software",
672 &metadata->stitching_software);
673 gst_tag_list_get_string(tags, "projection_type",
674 &metadata->projection_type_string);
675 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
676 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
677 gst_tag_list_get_int(tags, "init_view_heading",
678 &metadata->init_view_heading);
679 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
680 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
681 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
682 gst_tag_list_get_int(tags, "full_pano_width_pixels",
683 &metadata->full_pano_width_pixels);
684 gst_tag_list_get_int(tags, "full_pano_height_pixels",
685 &metadata->full_pano_height_pixels);
686 gst_tag_list_get_int(tags, "cropped_area_image_width",
687 &metadata->cropped_area_image_width);
688 gst_tag_list_get_int(tags, "cropped_area_image_height",
689 &metadata->cropped_area_image_height);
690 gst_tag_list_get_int(tags, "cropped_area_left",
691 &metadata->cropped_area_left);
692 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
693 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
694 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
695 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
699 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
702 /* macro for better code readability */
703 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
705 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
706 if (string != NULL) { \
707 SECURE_LOGD("update tag string : %s", string); \
708 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
709 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
710 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
711 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
712 mm_player_set_attribute((MMHandleType)player, NULL,\
713 playertag, new_string, strlen(new_string), NULL); \
714 MMPLAYER_FREEIF(new_string); \
716 mm_player_set_attribute((MMHandleType)player, NULL,\
717 playertag, string, strlen(string), NULL); \
719 MMPLAYER_FREEIF(string); \
724 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
726 GstSample *sample = NULL;\
727 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
728 GstMapInfo info = GST_MAP_INFO_INIT;\
729 buffer = gst_sample_get_buffer(sample);\
730 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
731 LOGD("failed to get image data from tag");\
732 gst_sample_unref(sample);\
735 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
736 MMPLAYER_FREEIF(player->album_art);\
737 player->album_art = (gchar *)g_malloc(info.size);\
738 if (player->album_art) {\
739 memcpy(player->album_art, info.data, info.size);\
740 mm_player_set_attribute((MMHandleType)player, NULL,\
741 playertag, (void *)player->album_art, info.size, NULL); \
742 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
743 msg_param.data = (void *)player->album_art;\
744 msg_param.size = info.size;\
745 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
746 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
749 gst_buffer_unmap(buffer, &info);\
750 gst_sample_unref(sample);\
754 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
756 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
759 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
760 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
761 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
762 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
763 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
765 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
766 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
767 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
768 mm_player_set_attribute((MMHandleType)player, NULL,\
769 "content_audio_bitrate", v_uint, NULL); \
770 player->bitrate[track_type] = v_uint; \
771 player->total_bitrate = 0; \
772 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
773 player->total_bitrate += player->bitrate[i]; \
774 mm_player_set_attribute((MMHandleType)player, NULL,\
775 playertag, player->total_bitrate, NULL); \
776 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
777 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
778 player->maximum_bitrate[track_type] = v_uint; \
779 player->total_maximum_bitrate = 0; \
780 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
781 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
782 mm_player_set_attribute((MMHandleType)player, NULL,\
783 playertag, player->total_maximum_bitrate, NULL); \
784 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
786 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
793 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
795 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
797 string = g_strdup_printf("%d", g_date_get_year(date));\
798 mm_player_set_attribute((MMHandleType)player, NULL,\
799 playertag, string, strlen(string), NULL); \
800 SECURE_LOGD("metainfo year : %s", string);\
801 MMPLAYER_FREEIF(string);\
807 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
809 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
810 if (datetime != NULL) {\
811 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
812 mm_player_set_attribute((MMHandleType)player, NULL,\
813 playertag, string, strlen(string), NULL); \
814 SECURE_LOGD("metainfo year : %s", string);\
815 MMPLAYER_FREEIF(string);\
816 gst_date_time_unref(datetime);\
822 GstTagList *tag_list = NULL;
827 GstDateTime *datetime = NULL;
829 GstBuffer *buffer = NULL;
831 MMMessageParamType msg_param = {0, };
833 /* currently not used. but those are needed for above macro */
834 //guint64 v_uint64 = 0;
835 //gdouble v_double = 0;
837 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
839 /* get tag list from gst message */
840 gst_message_parse_tag(msg, &tag_list);
842 /* store tags to player attributes */
843 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
844 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
845 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
846 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
847 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
848 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
849 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
850 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
851 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
852 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
853 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
854 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
855 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
856 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
857 MMPLAYER_UPDATE_TAG_LOCK(player);
858 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
859 MMPLAYER_UPDATE_TAG_UNLOCK(player);
860 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
862 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
863 if (player->video360_metadata.is_spherical == -1) {
864 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
865 mm_player_set_attribute((MMHandleType)player, NULL,
866 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
867 if (player->video360_metadata.is_spherical == 1) {
868 LOGD("This is spherical content for 360 playback.");
869 player->is_content_spherical = TRUE;
871 LOGD("This is not spherical content");
872 player->is_content_spherical = FALSE;
875 if (player->video360_metadata.projection_type_string) {
876 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
877 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
879 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
880 player->is_content_spherical = player->is_video360_enabled = FALSE;
884 if (player->video360_metadata.stereo_mode_string) {
885 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
886 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
887 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
888 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
889 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
890 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
892 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
893 player->is_content_spherical = player->is_video360_enabled = FALSE;
899 gst_tag_list_unref(tag_list);
904 /* if retval is FALSE, it will be dropped for performance. */
906 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
908 gboolean retval = FALSE;
910 if (!(player->pipeline && player->pipeline->mainbin)) {
911 LOGE("player pipeline handle is null");
915 switch (GST_MESSAGE_TYPE(message)) {
916 case GST_MESSAGE_TAG:
917 case GST_MESSAGE_EOS:
918 case GST_MESSAGE_ERROR:
919 case GST_MESSAGE_WARNING:
920 case GST_MESSAGE_CLOCK_LOST:
921 case GST_MESSAGE_NEW_CLOCK:
922 case GST_MESSAGE_ELEMENT:
923 case GST_MESSAGE_DURATION_CHANGED:
924 case GST_MESSAGE_ASYNC_START:
925 case GST_MESSAGE_STREAM_COLLECTION:
928 case GST_MESSAGE_ASYNC_DONE:
929 case GST_MESSAGE_STATE_CHANGED:
930 /* we only handle messages from pipeline */
931 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
936 case GST_MESSAGE_BUFFERING:
938 gint buffer_percent = 0;
941 gst_message_parse_buffering(message, &buffer_percent);
942 if (buffer_percent != MAX_BUFFER_PERCENT) {
943 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
947 if (!MMPLAYER_CMD_TRYLOCK(player)) {
948 LOGW("can't get cmd lock, send msg to bus");
952 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
953 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
954 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
957 MMPLAYER_CMD_UNLOCK(player);
961 case GST_MESSAGE_STREAMS_SELECTED:
963 if (MMPLAYER_USE_DECODEBIN(player))
964 break; /* drop msg */
966 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
967 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
968 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
970 gint64 dur_bytes = 0L;
972 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
973 LOGE("fail to get duration.");
975 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
976 * use file information was already set on Q2 when it was created. */
977 _mm_player_streaming_set_queue2(player->streamer,
978 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
979 TRUE, /* use_buffering */
980 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
981 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
984 LOGD("GST_MESSAGE_STREAMS_SELECTED");
985 player->no_more_pad = TRUE;
986 _mmplayer_set_reconfigure_state(player, FALSE);
987 _mmplayer_pipeline_complete(NULL, player);
1000 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1002 guint64 data_size = 0;
1003 gint64 pos_nsec = 0;
1005 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1007 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1009 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1010 data_size = player->http_content_size;
1013 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1014 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1020 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1022 int ret = MM_ERROR_NONE;
1023 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1024 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1025 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1026 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1028 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1029 LOGW("do nothing for buffering msg");
1030 ret = MM_ERROR_PLAYER_INVALID_STATE;
1034 prev_state = MMPLAYER_PREV_STATE(player);
1035 current_state = MMPLAYER_CURRENT_STATE(player);
1036 target_state = MMPLAYER_TARGET_STATE(player);
1037 pending_state = MMPLAYER_PENDING_STATE(player);
1039 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1040 MMPLAYER_STATE_GET_NAME(prev_state),
1041 MMPLAYER_STATE_GET_NAME(current_state),
1042 MMPLAYER_STATE_GET_NAME(pending_state),
1043 MMPLAYER_STATE_GET_NAME(target_state),
1044 player->streamer->buffering_state);
1046 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1047 /* NOTE : if buffering has done, player has to go to target state. */
1048 switch (target_state) {
1049 case MM_PLAYER_STATE_PAUSED:
1051 switch (pending_state) {
1052 case MM_PLAYER_STATE_PLAYING:
1053 _mmplayer_gst_pause(player, TRUE);
1056 case MM_PLAYER_STATE_PAUSED:
1057 LOGD("player is already going to paused state, there is nothing to do.");
1060 case MM_PLAYER_STATE_NONE:
1061 case MM_PLAYER_STATE_NULL:
1062 case MM_PLAYER_STATE_READY:
1064 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1070 case MM_PLAYER_STATE_PLAYING:
1072 switch (pending_state) {
1073 case MM_PLAYER_STATE_NONE:
1075 if (current_state != MM_PLAYER_STATE_PLAYING)
1076 _mmplayer_gst_resume(player, TRUE);
1080 case MM_PLAYER_STATE_PAUSED:
1081 /* NOTE: It should be worked as asynchronously.
1082 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1084 if (current_state == MM_PLAYER_STATE_PLAYING) {
1085 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1086 * The current state should be changed to paused purposely to prevent state conflict.
1088 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1090 _mmplayer_gst_resume(player, TRUE);
1093 case MM_PLAYER_STATE_PLAYING:
1094 LOGD("player is already going to playing state, there is nothing to do.");
1097 case MM_PLAYER_STATE_NULL:
1098 case MM_PLAYER_STATE_READY:
1100 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1106 case MM_PLAYER_STATE_NULL:
1107 case MM_PLAYER_STATE_READY:
1108 case MM_PLAYER_STATE_NONE:
1110 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1114 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1115 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1117 switch (pending_state) {
1118 case MM_PLAYER_STATE_NONE:
1120 if (current_state != MM_PLAYER_STATE_PAUSED) {
1121 /* rtsp streaming pause makes rtsp server stop sending data. */
1122 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1123 LOGD("set pause state during buffering");
1124 _mmplayer_gst_pause(player, TRUE);
1130 case MM_PLAYER_STATE_PLAYING:
1131 /* rtsp streaming pause makes rtsp server stop sending data. */
1132 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1133 _mmplayer_gst_pause(player, TRUE);
1136 case MM_PLAYER_STATE_PAUSED:
1139 case MM_PLAYER_STATE_NULL:
1140 case MM_PLAYER_STATE_READY:
1142 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1151 static stream_variant_t *
1152 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1154 stream_variant_t *var_info = NULL;
1155 g_return_val_if_fail(self != NULL, NULL);
1157 var_info = g_new0(stream_variant_t, 1);
1158 if (!var_info) return NULL;
1159 var_info->bandwidth = self->bandwidth;
1160 var_info->width = self->width;
1161 var_info->height = self->height;
1166 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1172 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1173 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1175 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1176 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1177 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1179 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1180 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1181 player->http_content_size = (bytes > 0) ? bytes : 0;
1184 /* handling audio clip which has vbr. means duration is keep changing */
1185 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1194 __mmplayer_eos_timer_cb(gpointer u_data)
1196 mmplayer_t *player = NULL;
1197 MMHandleType attrs = 0;
1200 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1202 player = (mmplayer_t *)u_data;
1203 attrs = MMPLAYER_GET_ATTRS(player);
1205 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1209 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1210 if (ret_value != MM_ERROR_NONE)
1211 LOGE("seeking to 0 failed in repeat play");
1214 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1217 /* we are returning FALSE as we need only one posting */
1222 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1224 MMPLAYER_RETURN_IF_FAIL(player);
1226 /* post now if delay is zero */
1227 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1228 LOGD("eos delay is zero. posting EOS now");
1229 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1231 if (player->audio_decoded_cb)
1232 _mmplayer_cancel_eos_timer(player);
1237 /* cancel if existing */
1238 _mmplayer_cancel_eos_timer(player);
1240 /* init new timeout */
1241 /* NOTE : consider give high priority to this timer */
1242 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1244 player->eos_timer = g_timeout_add(delay_in_ms,
1245 __mmplayer_eos_timer_cb, player);
1247 player->context.global_default = g_main_context_default();
1248 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1250 /* check timer is valid. if not, send EOS now */
1251 if (player->eos_timer == 0) {
1252 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1253 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1258 __mmplayer_gst_pending_seek(mmplayer_t *player)
1260 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1261 int ret = MM_ERROR_NONE;
1265 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1267 if (!player->pending_seek.is_pending) {
1268 LOGD("pending seek is not reserved. nothing to do.");
1272 /* check player state if player could pending seek or not. */
1273 current_state = MMPLAYER_CURRENT_STATE(player);
1275 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1276 LOGW("try to pending seek in %s state, try next time. ",
1277 MMPLAYER_STATE_GET_NAME(current_state));
1281 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1283 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1284 if (ret != MM_ERROR_NONE)
1285 LOGE("failed to seek pending position. just keep staying current position.");
1287 player->pending_seek.is_pending = false;
1295 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1297 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1299 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1301 audiobin = player->pipeline->audiobin; /* can be null */
1302 videobin = player->pipeline->videobin; /* can be null */
1303 textbin = player->pipeline->textbin; /* can be null */
1305 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1307 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1308 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1310 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1311 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1313 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1314 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1320 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1322 mmplayer_gst_element_t *textbin;
1325 MMPLAYER_RETURN_IF_FAIL(player &&
1327 player->pipeline->textbin);
1329 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1331 textbin = player->pipeline->textbin;
1334 LOGD("Drop subtitle text after getting EOS");
1336 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1337 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1339 player->is_subtitle_force_drop = TRUE;
1341 if (player->is_subtitle_force_drop == TRUE) {
1342 LOGD("Enable subtitle data path without drop");
1344 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1345 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1347 LOGD("non-connected with external display");
1349 player->is_subtitle_force_drop = FALSE;
1355 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1357 MMHandleType attrs = 0;
1362 /* NOTE : EOS event is coming multiple time. watch out it */
1363 /* check state. we only process EOS when pipeline state goes to PLAYING */
1364 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1365 LOGD("EOS received on non-playing state. ignoring it");
1369 if (player->pipeline && player->pipeline->textbin)
1370 __mmplayer_drop_subtitle(player, TRUE);
1372 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1373 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1375 /* rewind if repeat count is greater then zero */
1376 /* get play count */
1377 attrs = MMPLAYER_GET_ATTRS(player);
1379 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1381 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1383 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1384 if (player->playback_rate < 0.0) {
1385 player->resumed_by_rewind = TRUE;
1386 _mmplayer_set_mute((MMHandleType)player, false);
1387 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1390 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1393 player->sent_bos = FALSE;
1395 LOGD("do not post eos msg for repeating");
1400 if (player->pipeline)
1401 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1403 /* post eos message to application */
1404 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1406 /* reset last position */
1407 player->last_position = 0;
1414 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1416 GError *error = NULL;
1417 gchar *debug = NULL;
1421 /* generating debug info before returning error */
1422 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1424 /* get error code */
1425 gst_message_parse_error(msg, &error, &debug);
1427 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1428 /* Note : the streaming error from the streaming source is handled
1429 * using __mmplayer_handle_streaming_error.
1431 __mmplayer_handle_streaming_error(player, msg, error);
1433 /* dump state of all element */
1434 _mmplayer_dump_pipeline_state(player);
1436 /* translate gst error code to msl error code. then post it
1437 * to application if needed
1439 __mmplayer_handle_gst_error(player, msg, error);
1442 LOGE("error debug : %s", debug);
1445 MMPLAYER_FREEIF(debug);
1446 g_error_free(error);
1453 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1455 MMMessageParamType msg_param = {0, };
1456 int bRet = MM_ERROR_NONE;
1459 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1461 if (!MMPLAYER_IS_STREAMING(player)) {
1462 LOGW("this is not streaming playback.");
1466 MMPLAYER_CMD_LOCK(player);
1468 if (!player->streamer) {
1469 LOGW("Pipeline is shutting down");
1470 MMPLAYER_CMD_UNLOCK(player);
1474 /* ignore the remained buffering message till getting 100% msg */
1475 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1476 gint buffer_percent = 0;
1478 gst_message_parse_buffering(msg, &buffer_percent);
1480 if (buffer_percent == MAX_BUFFER_PERCENT) {
1481 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1482 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1483 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1485 MMPLAYER_CMD_UNLOCK(player);
1489 /* ignore the remained buffering message */
1490 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1491 gint buffer_percent = 0;
1493 gst_message_parse_buffering(msg, &buffer_percent);
1495 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1496 player->streamer->buffering_percent, buffer_percent);
1498 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1499 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1500 player->streamer->buffering_req.is_pre_buffering = FALSE;
1502 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1504 LOGD("interrupted buffering - ignored the remained buffering msg!");
1505 MMPLAYER_CMD_UNLOCK(player);
1510 __mmplayer_update_buffer_setting(player, msg);
1512 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1514 if (bRet == MM_ERROR_NONE) {
1515 msg_param.connection.buffering = player->streamer->buffering_percent;
1516 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1518 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1519 player->pending_resume &&
1520 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1522 player->is_external_subtitle_added_now = FALSE;
1523 player->pending_resume = FALSE;
1524 _mmplayer_resume((MMHandleType)player);
1527 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1528 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1530 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1531 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1532 player->seek_state = MMPLAYER_SEEK_NONE;
1533 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1534 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1535 /* Considering the async state transition in case of RTSP.
1536 After getting state change gst msg, seek completed msg will be posted. */
1537 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1541 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1542 if (!player->streamer) {
1543 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1544 MMPLAYER_CMD_UNLOCK(player);
1548 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1550 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1551 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1553 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1554 msg_param.connection.buffering = player->streamer->buffering_percent;
1555 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1557 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1560 msg_param.connection.buffering = player->streamer->buffering_percent;
1561 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1564 MMPLAYER_CMD_UNLOCK(player);
1572 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1574 mmplayer_gst_element_t *mainbin;
1575 const GValue *voldstate, *vnewstate, *vpending;
1576 GstState oldstate = GST_STATE_NULL;
1577 GstState newstate = GST_STATE_NULL;
1578 GstState pending = GST_STATE_NULL;
1581 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1583 mainbin = player->pipeline->mainbin;
1585 /* we only handle messages from pipeline */
1586 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1589 /* get state info from msg */
1590 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1591 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1592 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1594 if (!voldstate || !vnewstate) {
1595 LOGE("received msg has wrong format.");
1599 oldstate = (GstState)voldstate->data[0].v_int;
1600 newstate = (GstState)vnewstate->data[0].v_int;
1602 pending = (GstState)vpending->data[0].v_int;
1604 LOGD("state changed [%s] : %s ---> %s final : %s",
1605 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1606 gst_element_state_get_name((GstState)oldstate),
1607 gst_element_state_get_name((GstState)newstate),
1608 gst_element_state_get_name((GstState)pending));
1610 if (newstate == GST_STATE_PLAYING) {
1611 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1613 int retVal = MM_ERROR_NONE;
1614 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1616 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1618 if (MM_ERROR_NONE != retVal)
1619 LOGE("failed to seek pending position. just keep staying current position.");
1621 player->pending_seek.is_pending = false;
1625 if (oldstate == newstate) {
1626 LOGD("pipeline reports state transition to old state");
1631 case GST_STATE_PAUSED:
1633 gboolean prepare_async = FALSE;
1635 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1636 // managed prepare async case
1637 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1638 LOGD("checking prepare mode for async transition - %d", prepare_async);
1641 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1642 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1644 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1645 _mm_player_streaming_set_content_bitrate(player->streamer,
1646 player->total_maximum_bitrate, player->total_bitrate);
1648 if (player->pending_seek.is_pending) {
1649 LOGW("trying to do pending seek");
1650 MMPLAYER_CMD_LOCK(player);
1651 __mmplayer_gst_pending_seek(player);
1652 MMPLAYER_CMD_UNLOCK(player);
1658 case GST_STATE_PLAYING:
1660 if (MMPLAYER_IS_STREAMING(player)) {
1661 // managed prepare async case when buffering is completed
1662 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1663 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1664 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1665 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1667 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1669 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1670 if (player->streamer->buffering_percent < 100) {
1672 MMMessageParamType msg_param = {0, };
1673 LOGW("Posting Buffering Completed Message to Application !!!");
1675 msg_param.connection.buffering = 100;
1676 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1681 if (player->gapless.stream_changed) {
1682 _mmplayer_update_content_attrs(player, ATTR_ALL);
1683 player->gapless.stream_changed = FALSE;
1686 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1687 player->seek_state = MMPLAYER_SEEK_NONE;
1688 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1692 case GST_STATE_VOID_PENDING:
1693 case GST_STATE_NULL:
1694 case GST_STATE_READY:
1704 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1706 const gchar *structure_name;
1707 gint count = 0, idx = 0;
1710 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1712 if (gst_message_get_structure(msg) == NULL)
1715 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1716 if (!structure_name)
1719 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1721 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1722 const GValue *var_info = NULL;
1724 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1725 if (var_info != NULL) {
1726 if (player->adaptive_info.var_list)
1727 g_list_free_full(player->adaptive_info.var_list, g_free);
1729 /* share addr or copy the list */
1730 player->adaptive_info.var_list =
1731 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1733 count = g_list_length(player->adaptive_info.var_list);
1735 stream_variant_t *temp = NULL;
1737 /* print out for debug */
1738 LOGD("num of variant_info %d", count);
1739 for (idx = 0; idx < count; idx++) {
1740 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1742 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1748 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1749 gint num_buffers = 0;
1750 gint extra_num_buffers = 0;
1752 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1753 LOGD("video_num_buffers : %d", num_buffers);
1754 mm_player_set_attribute((MMHandleType)player, NULL,
1755 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1758 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1759 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1760 mm_player_set_attribute((MMHandleType)player, NULL,
1761 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1766 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1767 _mmplayer_track_update_text_attr_info(player, msg);
1769 /* custom message */
1770 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1771 MMMessageParamType msg_param = {0,};
1772 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1773 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1776 /* custom message for RTSP attribute :
1777 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1778 sdp which has contents info is received when rtsp connection is opened.
1779 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1780 if (!strcmp(structure_name, "rtspsrc_properties")) {
1781 g_autofree gchar *audio_codec = NULL;
1782 g_autofree gchar *video_codec = NULL;
1783 g_autofree gchar *video_frame_size = NULL;
1785 gst_structure_get(gst_message_get_structure(msg),
1786 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1787 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1788 player->streaming_type = _mmplayer_get_stream_service_type(player);
1790 gst_structure_get(gst_message_get_structure(msg),
1791 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1792 LOGD("rtsp_audio_codec : %s", audio_codec);
1794 mm_player_set_attribute((MMHandleType)player, NULL,
1795 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1797 gst_structure_get(gst_message_get_structure(msg),
1798 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1799 LOGD("rtsp_video_codec : %s", video_codec);
1801 mm_player_set_attribute((MMHandleType)player, NULL,
1802 "content_video_codec", video_codec, strlen(video_codec), NULL);
1804 gst_structure_get(gst_message_get_structure(msg),
1805 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1806 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1807 if (video_frame_size) {
1808 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1809 mm_player_set_attribute((MMHandleType)player, NULL,
1810 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1811 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1813 g_strfreev(res_str);
1822 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1824 mmplayer_gst_element_t *mainbin;
1827 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1829 mainbin = player->pipeline->mainbin;
1831 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1833 /* we only handle messages from pipeline */
1834 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1837 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1838 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1839 player->seek_state = MMPLAYER_SEEK_NONE;
1840 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1841 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1842 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1843 LOGD("sync %s state(%s) with parent state(%s)",
1844 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1845 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1846 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1848 /* In case of streaming, pause is required before finishing seeking by buffering.
1849 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1850 Because the buffering state is controlled according to the state transition for force resume,
1851 the decodebin state should be paused as player state. */
1852 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1855 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1856 (player->streamer) &&
1857 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1858 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1859 GstQuery *query = NULL;
1860 gboolean busy = FALSE;
1863 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1864 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1865 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1866 gst_query_parse_buffering_percent(query, &busy, &percent);
1867 gst_query_unref(query);
1869 LOGD("buffered percent(%s): %d",
1870 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1874 __mmplayer_handle_buffering_playback(player);
1877 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1886 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1888 GValue val = { 0, };
1890 guint indent = GPOINTER_TO_UINT(user_data);
1892 if (!gst_tag_list_copy_value(&val, tags, tag))
1895 if (G_VALUE_HOLDS_STRING(&val))
1896 str = g_value_dup_string(&val);
1898 str = gst_value_serialize(&val);
1900 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1902 g_value_unset(&val);
1906 __mmplayer_dump_collection(GstStreamCollection * collection)
1909 GstTagList *tags = NULL;
1910 GstCaps *caps = NULL;
1912 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1913 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1914 LOGD ("collection: Stream %u type %s flags 0x%x\n", i,
1915 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1916 gst_stream_get_stream_flags(stream));
1917 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1919 caps = gst_stream_get_caps(stream);
1921 gchar *caps_str = gst_caps_to_string(caps);
1922 LOGD (" caps: %s\n", caps_str);
1924 gst_caps_unref(caps);
1927 tags = gst_stream_get_tags(stream);
1930 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1931 gst_tag_list_unref(tags);
1937 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1938 GstStream *stream, GParamSpec *pspec, gpointer data)
1940 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1941 gst_stream_get_stream_id(stream), pspec->name, collection);
1942 if (g_str_equal(pspec->name, "caps")) {
1943 GstCaps *caps = gst_stream_get_caps(stream);
1944 gchar *caps_str = gst_caps_to_string(caps);
1945 LOGD (" New caps: %s\n", caps_str);
1947 gst_caps_unref(caps);
1950 if (g_str_equal (pspec->name, "tags")) {
1951 GstTagList *tags = gst_stream_get_tags(stream);
1954 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1955 gst_tag_list_unref(tags);
1961 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1963 mmplayer_t *player = (mmplayer_t *)(data);
1965 MMPLAYER_RETURN_IF_FAIL(player);
1966 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1968 switch (GST_MESSAGE_TYPE(msg)) {
1969 case GST_MESSAGE_UNKNOWN:
1970 LOGD("unknown message received");
1973 case GST_MESSAGE_EOS:
1974 LOGD("GST_MESSAGE_EOS received");
1975 __mmplayer_gst_handle_eos_message(player, msg);
1978 case GST_MESSAGE_ERROR:
1979 _mmplayer_set_reconfigure_state(player, FALSE);
1980 __mmplayer_gst_handle_error_message(player, msg);
1983 case GST_MESSAGE_WARNING:
1986 GError *error = NULL;
1988 gst_message_parse_warning(msg, &error, &debug);
1990 LOGD("warning : %s", error->message);
1991 LOGD("debug : %s", debug);
1993 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1995 MMPLAYER_FREEIF(debug);
1996 g_error_free(error);
2000 case GST_MESSAGE_TAG:
2002 LOGD("GST_MESSAGE_TAG");
2003 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2004 LOGW("failed to extract tags from gstmessage");
2008 case GST_MESSAGE_BUFFERING:
2009 __mmplayer_gst_handle_buffering_message(player, msg);
2012 case GST_MESSAGE_STATE_CHANGED:
2013 __mmplayer_gst_handle_state_message(player, msg);
2016 case GST_MESSAGE_CLOCK_LOST:
2018 GstClock *clock = NULL;
2019 gboolean need_new_clock = FALSE;
2021 gst_message_parse_clock_lost(msg, &clock);
2022 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2024 if (!player->videodec_linked)
2025 need_new_clock = TRUE;
2026 else if (!player->ini.use_system_clock)
2027 need_new_clock = TRUE;
2029 if (need_new_clock) {
2030 LOGD("Provide clock is TRUE, do pause->resume");
2031 _mmplayer_gst_pause(player, FALSE);
2032 _mmplayer_gst_resume(player, FALSE);
2037 case GST_MESSAGE_NEW_CLOCK:
2039 GstClock *clock = NULL;
2040 gst_message_parse_new_clock(msg, &clock);
2041 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2045 case GST_MESSAGE_ELEMENT:
2046 __mmplayer_gst_handle_element_message(player, msg);
2049 case GST_MESSAGE_DURATION_CHANGED:
2051 LOGD("GST_MESSAGE_DURATION_CHANGED");
2052 if (!__mmplayer_gst_handle_duration(player, msg))
2053 LOGW("failed to update duration");
2057 case GST_MESSAGE_ASYNC_START:
2058 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2061 case GST_MESSAGE_ASYNC_DONE:
2062 __mmplayer_gst_handle_async_done_message(player, msg);
2064 case GST_MESSAGE_STREAM_COLLECTION:
2066 GstStreamCollection *collection = NULL;
2067 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2069 gst_message_parse_stream_collection(msg, &collection);
2071 __mmplayer_dump_collection(collection);
2072 if (player->collection && player->stream_notify_id) {
2073 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2074 player->stream_notify_id = 0;
2076 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2077 if (player->collection) {
2078 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2079 (GCallback)__mmplayer_stream_notify_cb, player);
2081 gst_object_unref(collection);
2084 case GST_MESSAGE_STREAMS_SELECTED:
2086 GstStreamCollection *collection = NULL;
2087 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2089 gst_message_parse_streams_selected(msg, &collection);
2091 guint i = 0, len = 0;
2092 len = gst_message_streams_selected_get_size(msg);
2093 for (i = 0; i < len; i++) {
2094 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2095 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2096 gst_object_unref(stream);
2098 gst_object_unref (collection);
2103 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2104 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2105 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2106 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2107 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2108 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2109 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2110 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2111 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2112 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2113 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2114 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2115 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2116 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2117 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2124 /* should not call 'gst_message_unref(msg)' */
2128 static GstBusSyncReply
2129 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2131 mmplayer_t *player = (mmplayer_t *)data;
2132 GstBusSyncReply reply = GST_BUS_DROP;
2134 if (!(player->pipeline && player->pipeline->mainbin)) {
2135 LOGE("player pipeline handle is null");
2136 return GST_BUS_PASS;
2139 if (!__mmplayer_gst_check_useful_message(player, message)) {
2140 gst_message_unref(message);
2141 return GST_BUS_DROP;
2144 switch (GST_MESSAGE_TYPE(message)) {
2145 case GST_MESSAGE_TAG:
2146 __mmplayer_gst_extract_tag_from_msg(player, message);
2150 GstTagList *tags = NULL;
2152 gst_message_parse_tag(message, &tags);
2154 LOGE("TAGS received from element \"%s\".",
2155 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2157 gst_tag_list_foreach(tags, print_tag, NULL);
2158 gst_tag_list_unref(tags);
2166 case GST_MESSAGE_DURATION_CHANGED:
2167 __mmplayer_gst_handle_duration(player, message);
2169 case GST_MESSAGE_ELEMENT:
2171 const gchar *klass = NULL;
2172 klass = gst_element_factory_get_metadata
2173 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2174 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2175 reply = GST_BUS_PASS;
2178 __mmplayer_gst_handle_element_message(player, message);
2181 case GST_MESSAGE_ASYNC_DONE:
2182 /* NOTE:Don't call gst_callback directly
2183 * because previous frame can be showed even though this message is received for seek.
2186 reply = GST_BUS_PASS;
2190 if (reply == GST_BUS_DROP)
2191 gst_message_unref(message);
2197 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2199 GstElement *appsrc = element;
2200 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2201 GstBuffer *buffer = NULL;
2202 GstFlowReturn ret = GST_FLOW_OK;
2205 MMPLAYER_RETURN_IF_FAIL(element);
2206 MMPLAYER_RETURN_IF_FAIL(buf);
2208 buffer = gst_buffer_new();
2210 if (buf->offset < 0 || buf->len < 0) {
2211 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2215 if (buf->offset >= buf->len) {
2216 LOGD("call eos appsrc");
2217 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2221 if (buf->len - buf->offset < size)
2222 len = buf->len - buf->offset;
2224 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2225 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2226 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2229 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2231 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2237 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2239 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2241 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2243 buf->offset = (int)size;
2249 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2251 mmplayer_t *player = (mmplayer_t *)user_data;
2252 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2253 MMMessageParamType msg_param = {0,};
2254 guint64 current_level_bytes = 0;
2256 MMPLAYER_RETURN_IF_FAIL(player);
2258 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2259 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2260 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2261 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2263 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2267 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2269 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2271 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2272 msg_param.buffer_status.stream_type = stream_type;
2273 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2274 msg_param.buffer_status.bytes = current_level_bytes;
2276 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2280 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2282 mmplayer_t *player = (mmplayer_t *)user_data;
2283 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2284 MMMessageParamType msg_param = {0,};
2285 guint64 current_level_bytes = 0;
2287 MMPLAYER_RETURN_IF_FAIL(player);
2289 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2290 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2291 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2292 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2294 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2298 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2300 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2302 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2303 msg_param.buffer_status.stream_type = stream_type;
2304 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2305 msg_param.buffer_status.bytes = current_level_bytes;
2307 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2311 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2313 mmplayer_t *player = (mmplayer_t *)user_data;
2314 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2315 MMMessageParamType msg_param = {0,};
2317 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2319 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2320 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2321 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2322 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2324 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2328 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2330 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2331 msg_param.seek_data.stream_type = stream_type;
2332 msg_param.seek_data.offset = position;
2334 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2340 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2342 #define MAX_LEN_NAME 20
2344 gboolean ret = FALSE;
2345 GstPad *sinkpad = NULL;
2346 gchar *prefix = NULL;
2347 gchar dec_name[MAX_LEN_NAME] = {0, };
2348 main_element_id_e elem_id = MMPLAYER_M_NUM;
2350 mmplayer_gst_element_t *mainbin = NULL;
2351 GstElement *decodebin = NULL;
2352 GstCaps *dec_caps = NULL;
2356 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2358 player->pipeline->mainbin, FALSE);
2359 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2361 mainbin = player->pipeline->mainbin;
2363 case MM_PLAYER_STREAM_TYPE_AUDIO:
2365 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2367 case MM_PLAYER_STREAM_TYPE_VIDEO:
2369 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2372 LOGE("invalid type %d", type);
2376 if (mainbin[elem_id].gst) {
2377 LOGE("elem(%d) is already created", elem_id);
2381 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2383 /* create decodebin */
2384 decodebin = gst_element_factory_make("decodebin", dec_name);
2386 LOGE("failed to create %s", dec_name);
2390 /* raw pad handling signal */
2391 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2392 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2394 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2395 before looking for any elements that can handle that stream.*/
2396 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2397 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2399 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2400 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2401 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2403 /* This signal is emitted when a element is added to the bin.*/
2404 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2405 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2407 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2408 LOGE("failed to add new decodebin");
2412 dec_caps = gst_pad_query_caps(srcpad, NULL);
2415 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2417 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2418 gst_caps_unref(dec_caps);
2421 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2423 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2424 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2427 gst_object_unref(GST_OBJECT(sinkpad));
2429 gst_element_sync_state_with_parent(decodebin);
2431 mainbin[elem_id].id = elem_id;
2432 mainbin[elem_id].gst = decodebin;
2439 gst_object_unref(GST_OBJECT(sinkpad));
2442 gst_element_set_state(decodebin, GST_STATE_NULL);
2443 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2444 gst_object_unref(decodebin);
2452 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2454 #define MAX_LEN_NAME 20
2455 mmplayer_gst_element_t *mainbin = NULL;
2456 gchar *prefix = NULL;
2457 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2459 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2460 GstElement *src = NULL, *queue = NULL;
2461 GstPad *srcpad = NULL;
2464 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2465 player->pipeline->mainbin, FALSE);
2467 mainbin = player->pipeline->mainbin;
2469 LOGD("type(%d) path is creating", type);
2471 case MM_PLAYER_STREAM_TYPE_AUDIO:
2473 if (mainbin[MMPLAYER_M_SRC].gst)
2474 src_id = MMPLAYER_M_2ND_SRC;
2476 src_id = MMPLAYER_M_SRC;
2477 queue_id = MMPLAYER_M_A_BUFFER;
2479 case MM_PLAYER_STREAM_TYPE_VIDEO:
2481 src_id = MMPLAYER_M_SRC;
2482 queue_id = MMPLAYER_M_V_BUFFER;
2484 case MM_PLAYER_STREAM_TYPE_TEXT:
2485 prefix = "subtitle";
2486 src_id = MMPLAYER_M_SUBSRC;
2487 queue_id = MMPLAYER_M_S_BUFFER;
2490 LOGE("invalid type %d", type);
2494 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2495 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2498 src = gst_element_factory_make("appsrc", src_name);
2500 LOGF("failed to create %s", src_name);
2504 mainbin[src_id].id = src_id;
2505 mainbin[src_id].gst = src;
2507 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2508 "caps", caps, NULL);
2510 /* size of many video frames are larger than default blocksize as 4096 */
2511 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2512 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2514 if (player->media_stream_buffer_max_size[type] > 0)
2515 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2517 if (player->media_stream_buffer_min_percent[type] > 0)
2518 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2520 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2521 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2523 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2524 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2525 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2526 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2527 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2528 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2531 queue = gst_element_factory_make("queue2", queue_name);
2533 LOGE("failed to create %s", queue_name);
2536 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2538 mainbin[queue_id].id = queue_id;
2539 mainbin[queue_id].gst = queue;
2541 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2542 LOGE("failed to add src");
2546 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2547 LOGE("failed to add queue");
2551 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2552 LOGE("failed to link src and queue");
2556 /* create decoder */
2557 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2559 LOGE("failed to get srcpad of queue");
2563 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2564 _mmplayer_gst_create_decoder(player, srcpad, caps);
2566 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2567 LOGE("failed to create decoder");
2568 gst_object_unref(GST_OBJECT(srcpad));
2572 gst_object_unref(GST_OBJECT(srcpad));
2576 if (mainbin[src_id].gst) {
2577 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2578 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2579 gst_object_unref(mainbin[src_id].gst);
2580 mainbin[src_id].gst = NULL;
2583 if (mainbin[queue_id].gst) {
2584 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2585 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2586 gst_object_unref(mainbin[queue_id].gst);
2587 mainbin[queue_id].gst = NULL;
2594 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2596 GstPad *sinkpad = NULL;
2597 GstCaps *caps = NULL;
2598 GstElement *new_element = NULL;
2599 GstStructure *str = NULL;
2600 const gchar *name = NULL;
2602 mmplayer_t *player = (mmplayer_t *)data;
2606 MMPLAYER_RETURN_IF_FAIL(element && pad);
2607 MMPLAYER_RETURN_IF_FAIL(player &&
2609 player->pipeline->mainbin);
2611 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2612 * num_dynamic_pad will decreased after creating a sinkbin.
2614 player->num_dynamic_pad++;
2615 LOGD("stream count inc : %d", player->num_dynamic_pad);
2617 caps = gst_pad_query_caps(pad, NULL);
2618 MMPLAYER_CHECK_NULL(caps);
2620 str = gst_caps_get_structure(caps, 0);
2621 name = gst_structure_get_string(str, "media");
2623 LOGE("cannot get mimetype from structure.");
2627 if (strstr(name, "video")) {
2629 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2631 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2632 if (player->v_stream_caps) {
2633 gst_caps_unref(player->v_stream_caps);
2634 player->v_stream_caps = NULL;
2637 new_element = gst_element_factory_make("fakesink", NULL);
2638 player->num_dynamic_pad--;
2643 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2644 LOGE("failed to autoplug for caps");
2648 gst_caps_unref(caps);
2653 /* execute new_element if created*/
2655 LOGD("adding new element to pipeline");
2657 /* set state to READY before add to bin */
2658 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2660 /* add new element to the pipeline */
2661 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2662 LOGE("failed to add autoplug element to bin");
2666 /* get pad from element */
2667 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2669 LOGE("failed to get sinkpad from autoplug element");
2674 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2675 LOGE("failed to link autoplug element");
2679 gst_object_unref(sinkpad);
2682 /* run. setting PLAYING here since streaming source is live source */
2683 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2687 gst_caps_unref(caps);
2693 STATE_CHANGE_FAILED:
2695 /* FIXIT : take care if new_element has already added to pipeline */
2697 gst_object_unref(GST_OBJECT(new_element));
2700 gst_object_unref(GST_OBJECT(sinkpad));
2703 gst_caps_unref(caps);
2705 /* FIXIT : how to inform this error to MSL ????? */
2706 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2707 * then post an error to application
2712 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2714 mmplayer_t *player = (mmplayer_t *)data;
2718 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2719 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2720 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2721 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2723 * [1] audio and video will be dumped with filesink.
2724 * [2] autoplugging is done by just using pad caps.
2725 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2726 * and the video will be dumped via filesink.
2728 if (player->num_dynamic_pad == 0) {
2729 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2731 if (!_mmplayer_gst_remove_fakesink(player,
2732 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2733 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2734 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2735 * source element are not same. To overcome this situation, this function will called
2736 * several places and several times. Therefore, this is not an error case.
2741 /* create dot before error-return. for debugging */
2742 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2744 player->no_more_pad = TRUE;
2750 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2752 GstElement *element = NULL;
2753 gchar *user_agent = NULL;
2754 MMHandleType attrs = 0;
2757 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2759 /* get profile attribute */
2760 attrs = MMPLAYER_GET_ATTRS(player);
2762 LOGE("failed to get content attribute");
2766 element = gst_element_factory_make("rtspsrc", "rtsp source");
2768 LOGE("failed to create rtspsrc element");
2773 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2775 SECURE_LOGD("user_agent : %s", user_agent);
2777 /* setting property to streaming source */
2778 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2780 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2782 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2783 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2784 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2785 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2791 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2793 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2795 mmplayer_t *player = (mmplayer_t *)data;
2796 MMHandleType attrs = 0;
2797 gchar *user_agent, *cookies, **cookie_list;
2798 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2799 user_agent = cookies = NULL;
2803 MMPLAYER_RETURN_IF_FAIL(player);
2805 LOGD("source element %s", GST_ELEMENT_NAME(source));
2807 attrs = MMPLAYER_GET_ATTRS(player);
2809 LOGE("failed to get content attribute");
2813 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2814 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2816 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2817 http_timeout = player->ini.http_timeout;
2819 SECURE_LOGD("cookies : %s", cookies);
2820 SECURE_LOGD("user_agent : %s", user_agent);
2821 LOGD("timeout : %d", http_timeout);
2823 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2825 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2826 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2827 g_strfreev(cookie_list);
2831 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2837 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2839 mmplayer_t *player = (mmplayer_t *)data;
2840 gchar *user_agent = NULL;
2841 MMHandleType attrs = 0;
2844 MMPLAYER_RETURN_IF_FAIL(player);
2846 attrs = MMPLAYER_GET_ATTRS(player);
2848 LOGE("failed to get content attribute");
2852 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2854 SECURE_LOGD("user_agent : %s", user_agent);
2857 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2863 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2865 mmplayer_t *player = (mmplayer_t *)data;
2866 GstElement *source = NULL;
2869 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2871 g_object_get(orig, pspec->name, &source, NULL);
2873 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2874 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2876 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2877 __mmplayer_http_src_setup(source, data);
2878 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2879 __mmplayer_rtsp_src_setup(source, data);
2880 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2881 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2882 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2883 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2884 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2886 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2887 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2888 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2889 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2891 gst_object_unref (source);
2897 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2898 GstStream * stream, gpointer data)
2900 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2901 GstStreamType stype = gst_stream_get_stream_type(stream);
2902 mmplayer_t *player = (mmplayer_t *)data;
2903 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2904 GstCaps *caps = gst_stream_get_caps(stream);
2905 GstStructure *caps_structure = NULL;
2906 gchar *caps_str = NULL;
2908 LOGD("Stream type %s flags 0x%x",
2909 gst_stream_type_get_name(stype),
2910 gst_stream_get_stream_flags(stream));
2911 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2914 caps_str = gst_caps_to_string(caps);
2915 caps_structure = gst_caps_get_structure(caps, 0);
2916 const gchar *mime = gst_structure_get_name(caps_structure);
2918 LOGD(" caps: %s", caps_str);
2920 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2921 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2922 LOGW("skip [%s] by unsupported codec keyword [%s]",
2923 mime, player->ini.unsupported_codec_keyword[idx]);
2925 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2933 case GST_STREAM_TYPE_AUDIO:
2935 gint samplerate = 0;
2938 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2940 if (caps_structure) {
2941 gst_structure_get_int(caps_structure, "rate", &samplerate);
2942 gst_structure_get_int(caps_structure, "channels", &channels);
2944 if (channels > 0 && samplerate == 0) {
2945 LOGW("Skip corrupted audio stream");
2949 if (g_strrstr(caps_str, "mobile-xmf"))
2950 mm_player_set_attribute((MMHandleType)player, NULL,
2951 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2955 case GST_STREAM_TYPE_VIDEO:
2960 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2962 /* do not support multi track video */
2963 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2966 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2968 /* don't make video because of not required */
2969 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2970 (!player->set_mode.video_export)) {
2971 LOGD("no need video decoding, skip video stream");
2975 if (caps_structure) {
2976 gst_structure_get_int(caps_structure, "width", &width);
2979 if (player->v_stream_caps) {
2980 gst_caps_unref(player->v_stream_caps);
2981 player->v_stream_caps = NULL;
2984 player->v_stream_caps = gst_caps_copy(caps);
2985 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
2990 case GST_STREAM_TYPE_TEXT:
2991 type = MM_PLAYER_TRACK_TYPE_TEXT;
2994 LOGW("Skip not supported stream type");
2998 _mmplayer_track_update_stream(player, type, stream);
3000 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3001 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3002 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3003 _mmplayer_set_audio_attrs(player, caps);
3010 gst_caps_unref(caps);
3012 LOGD("ret %d", ret);
3017 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3018 GstStream * stream, gpointer data)
3020 mmplayer_t *player = (mmplayer_t *)data;
3021 GstStreamType stype = gst_stream_get_stream_type(stream);
3024 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3026 LOGD("stream type %s", gst_stream_type_get_name(stype));
3028 /* public does not support audio hw decoder at the moment */
3030 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3031 LOGW("video decoder resource is already acquired, skip it.");
3035 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3036 LOGE("failed to acquire video decoder resource");
3039 player->interrupted_by_resource = FALSE;
3045 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3047 GstIterator *iter = NULL;
3048 GValue item = {0, };
3049 GstElement *ch_element = NULL;
3050 GstElementFactory *ch_factory = NULL;
3053 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3055 iter = gst_bin_iterate_recurse(bin);
3056 MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3058 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3059 ch_element = g_value_get_object(&item);
3060 ch_factory = gst_element_get_factory(ch_element);
3061 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3062 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3063 LOGD("Find %s element", element_name);
3067 g_value_reset(&item);
3069 gst_iterator_free(iter);
3076 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3078 gchar *factory_name = NULL;
3079 mmplayer_t *player = (mmplayer_t *)data;
3080 mmplayer_gst_element_t *mainbin = NULL;
3083 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3085 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3086 mainbin = player->pipeline->mainbin;
3088 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3089 factory_name, GST_ELEMENT_NAME(element));
3091 /* keep the first typefind reference only */
3092 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+
3093 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3094 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3096 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3097 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3098 LOGD("typefind reference is added");
3102 if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3103 /* update queue2 setting */
3104 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3105 gint64 dur_bytes = 0L;
3106 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3108 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3109 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3111 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3112 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3114 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3115 /* NOTE : in case of ts streaming, player could not get the correct duration info *
3116 * skip the pull mode(file or ring buffering) setting. */
3117 if (dur_bytes > 0) {
3118 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
3119 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3120 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3126 _mm_player_streaming_set_queue2(player->streamer,
3130 (guint64)dur_bytes); /* no meaning at the moment */
3135 if (g_strrstr(factory_name, "parsebin")) {
3136 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3137 GstElement *ch_element = __mmplayer_gst_find_child_element(child, "multiqueue");
3139 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3140 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3142 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3143 if (MMPLAYER_IS_STREAMING(player)) {
3144 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3146 g_object_set(G_OBJECT(ch_element),
3147 "max-size-time", (guint64)(5 * GST_SECOND),
3148 "use-interleave", FALSE, NULL);
3152 int video_codec_type = 0;
3153 int audio_codec_type = 0;
3155 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3156 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3157 if (player->type_caps &&
3158 !MMPLAYER_IS_HTTP_LIVE_STREAMING(player) &&
3159 !MMPLAYER_IS_DASH_STREAMING(player))
3160 g_object_set(G_OBJECT(element), "sink-caps", player->type_caps, NULL);
3162 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3163 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3165 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3166 and codec default type in ini has to be hw.
3168 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3169 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3170 g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL);
3171 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3172 g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL);
3174 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3175 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3176 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3177 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3179 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3180 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3182 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3183 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3185 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3186 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3189 _mmplayer_gst_element_added((GstElement *)child, element, data);
3195 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3199 MMPLAYER_RETURN_IF_FAIL(player);
3200 MMPLAYER_RETURN_IF_FAIL(removed_element);
3202 LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3204 for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3205 GList *node = player->signals[type];
3207 GList *next_node = node->next;
3208 mmplayer_signal_item_t *item = node->data;
3209 if (item && item->obj == G_OBJECT(removed_element)) {
3210 player->signals[type] = g_list_delete_link(player->signals[type], node);
3211 MMPLAYER_FREEIF(item);
3221 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3223 mmplayer_t *player = (mmplayer_t *)data;
3227 MMPLAYER_RETURN_IF_FAIL(player);
3229 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3231 __mmplayer_delete_signal_connection(player, element);
3237 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3239 GstElement *uridecodebin3 = NULL;
3242 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3244 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3245 if (!uridecodebin3) {
3246 LOGE("failed to create uridecodebin3");
3251 SECURE_LOGD("uri : %s", player->profile.uri);
3253 /* setting property to streaming source */
3254 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3255 "message-forward", TRUE,
3256 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3258 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3259 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3261 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3262 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3264 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3265 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3267 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3268 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3270 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3271 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3273 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3274 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3276 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3277 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3279 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3280 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3282 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3283 LOGW("[DASH] this is still experimental feature");
3286 return uridecodebin3;
3290 __mmplayer_gst_make_http_src(mmplayer_t *player)
3292 #define MAX_RETRY_COUNT 10
3293 GstElement *element = NULL;
3294 MMHandleType attrs = 0;
3295 gchar *user_agent, *cookies, **cookie_list;
3296 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3298 user_agent = cookies = NULL;
3302 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3304 /* get profile attribute */
3305 attrs = MMPLAYER_GET_ATTRS(player);
3307 LOGE("failed to get content attribute");
3311 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3313 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3315 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3320 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3321 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3323 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3324 http_timeout = player->ini.http_timeout;
3327 SECURE_LOGD("location : %s", player->profile.uri);
3328 SECURE_LOGD("cookies : %s", cookies);
3329 SECURE_LOGD("user_agent : %s", user_agent);
3330 LOGD("timeout : %d", http_timeout);
3332 /* setting property to streaming source */
3333 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3334 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3335 "retries", MAX_RETRY_COUNT, NULL);
3337 /* parsing cookies */
3338 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3339 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3340 g_strfreev(cookie_list);
3344 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3346 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3347 LOGW("[DASH] this is still experimental feature");
3354 __mmplayer_gst_make_file_src(mmplayer_t *player)
3356 GstElement *element = NULL;
3359 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3361 LOGD("using filesrc for 'file://' handler");
3362 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3363 LOGE("failed to get storage info");
3367 element = gst_element_factory_make("filesrc", "source");
3369 LOGE("failed to create filesrc");
3373 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3380 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3382 mmplayer_t *player = (mmplayer_t *)data;
3384 g_return_val_if_fail(player, FALSE);
3385 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3386 gst_message_ref(msg);
3388 g_mutex_lock(&player->bus_msg_q_lock);
3389 g_queue_push_tail(player->bus_msg_q, msg);
3390 g_mutex_unlock(&player->bus_msg_q_lock);
3392 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3393 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3394 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3398 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3400 mmplayer_t *player = (mmplayer_t *)(data);
3401 GstMessage *msg = NULL;
3404 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3406 player->pipeline->mainbin &&
3407 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3410 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3412 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3413 while (!player->bus_msg_thread_exit) {
3414 g_mutex_lock(&player->bus_msg_q_lock);
3415 msg = g_queue_pop_head(player->bus_msg_q);
3416 g_mutex_unlock(&player->bus_msg_q_lock);
3418 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3421 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3422 /* handle the gst msg */
3423 __mmplayer_gst_bus_msg_callback(msg, player);
3424 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3425 gst_message_unref(msg);
3428 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3435 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3437 gint64 dur_nsec = 0;
3438 gint64 pos_nsec = 0;
3441 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3443 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3444 return MM_ERROR_NONE;
3446 /* NOTE : duration cannot be zero except live streaming.
3447 * Since some element could have some timing problem with querying duration, try again.
3449 if (player->duration == 0) {
3450 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3451 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3452 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3453 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3454 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3455 player->pending_seek.is_pending = true;
3456 player->pending_seek.pos = position;
3457 player->seek_state = MMPLAYER_SEEK_NONE;
3458 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3459 return MM_ERROR_PLAYER_NO_OP;
3461 player->seek_state = MMPLAYER_SEEK_NONE;
3462 return MM_ERROR_PLAYER_SEEK;
3465 player->duration = dur_nsec;
3468 if (player->duration > 0 && player->duration < position) {
3469 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3470 return MM_ERROR_INVALID_ARGUMENT;
3473 if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3474 if ((pos_nsec == player->duration) && /* current pos is end of stream */
3475 ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3476 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3477 player->seek_state = MMPLAYER_SEEK_NONE;
3478 return MM_ERROR_PLAYER_NO_OP;
3483 return MM_ERROR_NONE;
3487 __mmplayer_gst_check_seekable(mmplayer_t *player)
3489 GstQuery *query = NULL;
3490 gboolean seekable = FALSE;
3492 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3496 query = gst_query_new_seeking(GST_FORMAT_TIME);
3497 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3498 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3499 gst_query_unref(query);
3502 LOGW("non-seekable content");
3503 player->seek_state = MMPLAYER_SEEK_NONE;
3507 LOGW("failed to get seeking query");
3508 gst_query_unref(query); /* keep seeking operation */
3515 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3517 GstState element_state = GST_STATE_VOID_PENDING;
3518 GstState element_pending_state = GST_STATE_VOID_PENDING;
3519 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3523 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3524 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3526 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3529 ret = gst_element_set_state(element, state);
3530 if (ret == GST_STATE_CHANGE_FAILURE) {
3531 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3533 /* dump state of all element */
3534 _mmplayer_dump_pipeline_state(player);
3536 return MM_ERROR_PLAYER_INTERNAL;
3539 /* return here so state transition to be done in async mode */
3541 LOGD("async state transition. not waiting for state complete.");
3542 return MM_ERROR_NONE;
3545 /* wait for state transition */
3546 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3547 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3548 LOGE("failed to change [%s] element state to [%s] within %d sec",
3549 GST_ELEMENT_NAME(element),
3550 gst_element_state_get_name(state), timeout);
3552 LOGE(" [%s] state : %s pending : %s",
3553 GST_ELEMENT_NAME(element),
3554 gst_element_state_get_name(element_state),
3555 gst_element_state_get_name(element_pending_state));
3557 /* dump state of all element */
3558 _mmplayer_dump_pipeline_state(player);
3560 return MM_ERROR_PLAYER_INTERNAL;
3563 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3567 return MM_ERROR_NONE;
3571 _mmplayer_gst_start(mmplayer_t *player)
3573 int ret = MM_ERROR_NONE;
3574 gboolean async = FALSE;
3578 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3580 /* NOTE : if SetPosition was called before Start. do it now
3581 * streaming doesn't support it. so it should be always sync
3582 * !!create one more api to check if there is pending seek rather than checking variables
3584 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3585 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3586 ret = _mmplayer_gst_pause(player, FALSE);
3587 if (ret != MM_ERROR_NONE) {
3588 LOGE("failed to set state to PAUSED for pending seek");
3592 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3593 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3594 LOGW("failed to seek pending position. starting from the begin of content");
3597 LOGD("current state before doing transition");
3598 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3599 MMPLAYER_PRINT_STATE(player);
3601 /* set pipeline state to PLAYING */
3602 ret = _mmplayer_gst_set_state(player,
3603 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3604 if (ret != MM_ERROR_NONE) {
3605 LOGE("failed to set state to PLAYING");
3609 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3611 /* generating debug info before returning error */
3612 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3620 _mmplayer_gst_stop(mmplayer_t *player)
3622 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3623 MMHandleType attrs = 0;
3624 gboolean rewind = FALSE;
3626 int ret = MM_ERROR_NONE;
3630 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3631 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3633 LOGD("current state before doing transition");
3634 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3635 MMPLAYER_PRINT_STATE(player);
3637 attrs = MMPLAYER_GET_ATTRS(player);
3639 LOGE("cannot get content attribute");
3640 return MM_ERROR_PLAYER_INTERNAL;
3643 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3644 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3646 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3647 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3650 if (player->es_player_push_mode)
3651 /* disable the async state transition because there could be no data in the pipeline */
3652 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3655 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3657 if (player->es_player_push_mode) {
3658 /* enable the async state transition as default operation */
3659 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3662 /* return if set_state has failed */
3663 if (ret != MM_ERROR_NONE) {
3664 LOGE("failed to set state.");
3670 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3671 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3672 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3673 LOGW("failed to rewind");
3674 ret = MM_ERROR_PLAYER_SEEK;
3679 player->sent_bos = FALSE;
3681 if (player->es_player_push_mode) //for cloudgame
3684 /* wait for seek to complete */
3685 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3686 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3687 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3689 LOGE("fail to stop player.");
3690 ret = MM_ERROR_PLAYER_INTERNAL;
3691 _mmplayer_dump_pipeline_state(player);
3694 /* generate dot file if enabled */
3695 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3703 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3705 int ret = MM_ERROR_NONE;
3709 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3710 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3712 LOGD("current state before doing transition");
3713 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3714 MMPLAYER_PRINT_STATE(player);
3716 /* set pipeline status to PAUSED */
3717 ret = _mmplayer_gst_set_state(player,
3718 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3723 if (ret != MM_ERROR_NONE) {
3724 GstMessage *msg = NULL;
3725 GTimer *timer = NULL;
3726 gdouble MAX_TIMEOUT_SEC = 3;
3728 LOGE("failed to set state to PAUSED");
3730 if (!player->bus_watcher) {
3731 LOGE("there is no bus msg thread. pipeline is shutting down.");
3735 if (player->msg_posted) {
3736 LOGE("error msg is already posted.");
3740 timer = g_timer_new();
3741 g_timer_start(timer);
3743 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3746 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3748 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3749 GError *error = NULL;
3751 /* parse error code */
3752 gst_message_parse_error(msg, &error, NULL);
3754 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3755 /* Note : the streaming error from the streaming source is handled
3756 * using __mmplayer_handle_streaming_error.
3758 __mmplayer_handle_streaming_error(player, msg, error);
3761 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3763 if (error->domain == GST_STREAM_ERROR)
3764 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3765 else if (error->domain == GST_RESOURCE_ERROR)
3766 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3767 else if (error->domain == GST_LIBRARY_ERROR)
3768 ret = __mmplayer_gst_handle_library_error(player, error->code);
3769 else if (error->domain == GST_CORE_ERROR)
3770 ret = __mmplayer_gst_handle_core_error(player, error->code);
3772 g_error_free(error);
3774 player->msg_posted = TRUE;
3776 gst_message_unref(msg);
3778 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3780 gst_object_unref(bus);
3781 g_timer_stop(timer);
3782 g_timer_destroy(timer);
3787 if (MMPLAYER_USE_DECODEBIN(player)) {
3788 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3789 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3790 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3793 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3796 /* generate dot file before returning error */
3797 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3805 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3807 int ret = MM_ERROR_NONE;
3812 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3813 MM_ERROR_PLAYER_NOT_INITIALIZED);
3815 LOGD("current state before doing transition");
3816 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3817 MMPLAYER_PRINT_STATE(player);
3820 LOGD("do async state transition to PLAYING");
3822 /* set pipeline state to PLAYING */
3823 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3825 ret = _mmplayer_gst_set_state(player,
3826 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3827 if (ret != MM_ERROR_NONE) {
3828 LOGE("failed to set state to PLAYING");
3833 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3836 /* generate dot file */
3837 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3844 /* sending event to one of sinkelements */
3846 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3848 GstEvent *event2 = NULL;
3849 GList *sinks = NULL;
3850 gboolean res = FALSE;
3853 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3854 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3856 /* While adding subtitles in live feeds seek is getting called.
3857 Adding defensive check in framework layer.*/
3858 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3859 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3860 LOGE("Should not send seek event during live playback");
3865 if (player->play_subtitle)
3866 event2 = gst_event_copy((const GstEvent *)event);
3868 sinks = player->sink_elements;
3870 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3872 if (GST_IS_ELEMENT(sink)) {
3873 /* keep ref to the event */
3874 gst_event_ref(event);
3876 if ((res = gst_element_send_event(sink, event))) {
3877 LOGD("sending event[%s] to sink element [%s] success!",
3878 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3880 /* rtsp case, async_done is not called after seek during pause state */
3881 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3882 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3883 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3884 LOGD("RTSP seek completed, after pause state..");
3885 player->seek_state = MMPLAYER_SEEK_NONE;
3886 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3892 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3893 sinks = g_list_next(sinks);
3900 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3901 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3904 sinks = g_list_next(sinks);
3907 /* Note : Textbin is not linked to the video or audio bin.
3908 * It needs to send the event to the text sink seperately.
3910 if (player->play_subtitle && player->pipeline) {
3911 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3913 if (GST_IS_ELEMENT(text_sink)) {
3914 /* keep ref to the event */
3915 gst_event_ref(event2);
3917 if ((res = gst_element_send_event(text_sink, event2)))
3918 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3919 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3921 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3922 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3924 gst_event_unref(event2);
3928 gst_event_unref(event);
3936 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3937 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3938 gint64 cur, GstSeekType stop_type, gint64 stop)
3940 GstEvent *event = NULL;
3941 gboolean result = FALSE;
3945 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3947 if (player->pipeline && player->pipeline->textbin)
3948 __mmplayer_drop_subtitle(player, FALSE);
3950 event = gst_event_new_seek(rate, format, flags, cur_type,
3951 cur, stop_type, stop);
3953 result = _mmplayer_gst_send_event_to_sink(player, event);
3961 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3963 int ret = MM_ERROR_NONE;
3964 gint64 pos_nsec = 0;
3965 gboolean accurate = FALSE;
3966 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3969 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3970 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3972 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3973 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3976 ret = __mmplayer_gst_check_position(player, position);
3977 if (ret != MM_ERROR_NONE) {
3978 LOGW("result of check position info 0x%X", ret);
3979 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3982 if (!__mmplayer_gst_check_seekable(player))
3983 return MM_ERROR_PLAYER_NO_OP;
3985 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3986 position, player->playback_rate, player->duration);
3988 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3989 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3990 This causes problem is position calculation during normal pause resume scenarios also.
3991 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3992 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3993 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3994 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3995 LOGW("getting current position failed in seek");
3997 player->last_position = pos_nsec;
3998 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
4001 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4002 LOGD("not completed seek");
4003 return MM_ERROR_PLAYER_DOING_SEEK;
4006 if (!internal_called)
4007 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
4009 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
4010 that's why set position through property. */
4011 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
4012 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
4013 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
4014 (!player->videodec_linked) && (!player->audiodec_linked)) {
4016 LOGD("[%s] set position =%"GST_TIME_FORMAT,
4017 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
4019 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
4020 player->seek_state = MMPLAYER_SEEK_NONE;
4021 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4023 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4025 seek_flags |= GST_SEEK_FLAG_ACCURATE;
4027 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4029 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4030 GST_FORMAT_TIME, seek_flags,
4031 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4032 LOGE("failed to set position");
4037 /* NOTE : store last seeking point to overcome some bad operation
4038 * (returning zero when getting current position) of some elements
4040 player->last_position = position;
4042 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4043 if (player->playback_rate > 1.0)
4044 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4046 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4047 LOGD("buffering should be reset after seeking");
4048 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4049 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4053 return MM_ERROR_NONE;
4056 player->pending_seek.is_pending = true;
4057 player->pending_seek.pos = position;
4059 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4060 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4061 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4062 player->pending_seek.pos);
4064 return MM_ERROR_NONE;
4067 player->seek_state = MMPLAYER_SEEK_NONE;
4068 return MM_ERROR_PLAYER_SEEK;
4072 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4074 #define TRICKPLAY_OFFSET GST_MSECOND
4076 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4077 gint64 pos_nsec = 0;
4078 gboolean ret = TRUE;
4080 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4081 MM_ERROR_PLAYER_NOT_INITIALIZED);
4083 current_state = MMPLAYER_CURRENT_STATE(player);
4085 /* NOTE : query position except paused state to overcome some bad operation
4086 * please refer to below comments in details
4088 if (current_state != MM_PLAYER_STATE_PAUSED)
4089 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4091 /* NOTE : get last point to overcome some bad operation of some elements
4092 *(returning zero when getting current position in paused state
4093 * and when failed to get position during seeking
4095 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4096 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4098 if (player->playback_rate < 0.0)
4099 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4101 pos_nsec = player->last_position;
4104 pos_nsec = player->last_position;
4106 player->last_position = pos_nsec;
4108 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4111 if (player->duration > 0 && pos_nsec > player->duration)
4112 pos_nsec = player->duration;
4114 player->last_position = pos_nsec;
4117 *position = pos_nsec;
4119 return MM_ERROR_NONE;
4123 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4125 #define STREAMING_IS_FINISHED 0
4126 #define BUFFERING_MAX_PER 100
4127 #define DEFAULT_PER_VALUE -1
4128 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4130 mmplayer_gst_element_t *mainbin = NULL;
4131 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4132 gint64 buffered_total = 0;
4133 gint64 position = 0;
4134 gint buffered_sec = -1;
4135 GstBufferingMode mode = GST_BUFFERING_STREAM;
4136 gint64 content_size_time = player->duration;
4137 guint64 content_size_bytes = player->http_content_size;
4139 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4141 player->pipeline->mainbin,
4142 MM_ERROR_PLAYER_NOT_INITIALIZED);
4144 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4149 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4150 /* and rtsp is not ready yet. */
4151 LOGW("it's only used for http streaming case");
4152 return MM_ERROR_PLAYER_NO_OP;
4155 if (content_size_time <= 0 || content_size_bytes <= 0) {
4156 LOGW("there is no content size");
4157 return MM_ERROR_NONE;
4160 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4161 LOGW("fail to get current position");
4162 return MM_ERROR_NONE;
4165 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4166 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4168 mainbin = player->pipeline->mainbin;
4169 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4171 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4172 GstQuery *query = NULL;
4173 gint byte_in_rate = 0, byte_out_rate = 0;
4174 gint64 estimated_total = 0;
4176 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4177 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4178 LOGW("fail to get buffering query from queue2");
4180 gst_query_unref(query);
4181 return MM_ERROR_NONE;
4184 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4185 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4187 if (mode == GST_BUFFERING_STREAM) {
4188 /* using only queue in case of push mode(ts / mp3) */
4189 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4190 GST_FORMAT_BYTES, &buffered_total)) {
4191 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4192 end_per = 100 * buffered_total / content_size_bytes;
4195 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4197 guint num_of_ranges = 0;
4198 gint64 start_byte = 0, stop_byte = 0;
4200 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4201 if (estimated_total != STREAMING_IS_FINISHED) {
4202 /* buffered size info from queue2 */
4203 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4204 for (idx = 0; idx < num_of_ranges; idx++) {
4205 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4206 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4208 buffered_total += (stop_byte - start_byte);
4211 end_per = BUFFERING_MAX_PER;
4214 gst_query_unref(query);
4217 if (end_per == DEFAULT_PER_VALUE) {
4218 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4220 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4222 /* buffered size info from multiqueue */
4223 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4224 guint curr_size_bytes = 0;
4225 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4226 "curr-size-bytes", &curr_size_bytes, NULL);
4227 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4228 buffered_total += curr_size_bytes;
4231 if (avg_byterate > 0)
4232 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4233 else if (player->total_maximum_bitrate > 0)
4234 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4235 else if (player->total_bitrate > 0)
4236 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4238 if (buffered_sec >= 0)
4239 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4243 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4244 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4246 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4247 buffered_total, buffered_sec, *start_pos, *end_pos);
4249 return MM_ERROR_NONE;
4253 _mmplayer_gst_create_source(mmplayer_t *player)
4255 GstElement *element = NULL;
4258 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4259 player->pipeline->mainbin, NULL);
4261 /* setup source for gapless play */
4262 switch (player->profile.uri_type) {
4264 case MM_PLAYER_URI_TYPE_FILE:
4265 element = __mmplayer_gst_make_file_src(player);
4267 case MM_PLAYER_URI_TYPE_URL_HTTP:
4268 element = __mmplayer_gst_make_http_src(player);
4271 LOGE("not support uri type %d", player->profile.uri_type);
4276 LOGE("failed to create source element");
4285 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4288 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4289 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4291 SECURE_LOGD("uri : %s", player->profile.uri);
4293 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4295 if ((player->v_stream_caps) &&
4296 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4297 return MM_ERROR_PLAYER_INTERNAL;
4299 if ((player->a_stream_caps) &&
4300 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4301 return MM_ERROR_PLAYER_INTERNAL;
4303 if ((player->s_stream_caps) &&
4304 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4305 return MM_ERROR_PLAYER_INTERNAL;
4308 return MM_ERROR_NONE;
4312 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4314 mmplayer_gst_element_t *mainbin = NULL;
4315 GstElement *autoplug_elem = NULL;
4318 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4319 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4321 mainbin = player->pipeline->mainbin;
4323 LOGD("uri type %d", player->profile.uri_type);
4325 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4326 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4327 return MM_ERROR_PLAYER_INTERNAL;
4330 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4331 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4334 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4335 if (!autoplug_elem) {
4336 LOGE("failed to create uridecodebin3 element");
4340 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4341 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4342 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4344 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4345 LOGE("failed to add uridecodebin to pipeline");
4349 /* FIXME: required ?*/
4350 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4351 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4352 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4354 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4355 LOGE("failed to create fakesink");
4358 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4360 /* take ownership of fakesink. we are reusing it */
4361 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4363 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4364 LOGE("failed to add fakesink to bin");
4365 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4370 return MM_ERROR_NONE;
4374 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4375 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4377 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4378 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4380 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4381 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4383 return MM_ERROR_PLAYER_INTERNAL;
4387 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4389 mmplayer_gst_element_t *mainbin = NULL;
4390 GstElement *src_elem = NULL;
4391 GstElement *autoplug_elem = NULL;
4392 GList *element_bucket = NULL;
4393 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4396 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4397 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4399 LOGD("uri type %d", player->profile.uri_type);
4401 /* create source element */
4402 switch (player->profile.uri_type) {
4403 case MM_PLAYER_URI_TYPE_URL_RTSP:
4404 src_elem = __mmplayer_gst_make_rtsp_src(player);
4406 case MM_PLAYER_URI_TYPE_URL_HTTP:
4407 src_elem = __mmplayer_gst_make_http_src(player);
4409 case MM_PLAYER_URI_TYPE_FILE:
4410 src_elem = __mmplayer_gst_make_file_src(player);
4412 case MM_PLAYER_URI_TYPE_SS:
4414 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4415 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4417 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4421 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4422 LOGD("get timeout from ini");
4423 http_timeout = player->ini.http_timeout;
4426 /* setting property to streaming source */
4427 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4430 case MM_PLAYER_URI_TYPE_MEM:
4432 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4434 src_elem = gst_element_factory_make("appsrc", "mem-source");
4436 LOGE("failed to create appsrc element");
4440 g_object_set(src_elem, "stream-type", stream_type,
4441 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4443 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4444 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4445 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4446 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4450 LOGE("not support uri type");
4455 LOGE("failed to create source element");
4456 return MM_ERROR_PLAYER_INTERNAL;
4459 mainbin = player->pipeline->mainbin;
4461 /* take source element */
4462 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4464 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4465 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4466 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4468 /* create next element for auto-plugging */
4469 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4470 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4471 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4472 if (!autoplug_elem) {
4473 LOGE("failed to create typefind element");
4477 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4478 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4479 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4480 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4481 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4482 if (!autoplug_elem) {
4483 LOGE("failed to create decodebin");
4487 /* default size of mq in decodebin is 2M
4488 * but it can cause blocking issue during seeking depends on content. */
4489 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4492 if (autoplug_elem) {
4493 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4494 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4495 mainbin[autoplug_elem_id].gst = autoplug_elem;
4497 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4500 /* add elements to pipeline */
4501 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4502 LOGE("failed to add elements to pipeline");
4506 /* linking elements in the bucket by added order. */
4507 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4508 LOGE("failed to link some elements");
4512 /* FIXME: need to check whether this is required or not. */
4513 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4514 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4515 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4516 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4517 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4519 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4520 LOGE("failed to create fakesink");
4523 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4525 /* take ownership of fakesink. we are reusing it */
4526 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4528 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4529 LOGE("failed to add fakesink to bin");
4530 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4535 g_list_free(element_bucket);
4538 return MM_ERROR_NONE;
4541 g_list_free(element_bucket);
4543 if (mainbin[MMPLAYER_M_SRC].gst)
4544 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4546 if (mainbin[autoplug_elem_id].gst)
4547 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4549 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4550 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4552 mainbin[MMPLAYER_M_SRC].gst = NULL;
4553 mainbin[autoplug_elem_id].gst = NULL;
4554 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4556 return MM_ERROR_PLAYER_INTERNAL;
4560 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4563 mmplayer_gst_element_t *mainbin = NULL;
4566 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4567 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4569 mainbin = player->pipeline->mainbin;
4571 /* connect bus callback */
4572 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4574 LOGE("cannot get bus from pipeline");
4575 return MM_ERROR_PLAYER_INTERNAL;
4578 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4579 (GstBusFunc)__mmplayer_gst_msg_push, player,
4580 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4581 if (player->bus_watcher == 0) {
4582 LOGE("failed to add bus watch");
4583 return MM_ERROR_PLAYER_INTERNAL;
4586 g_mutex_init(&player->bus_watcher_mutex);
4587 g_cond_init(&player->bus_watcher_cond);
4589 player->context.thread_default = g_main_context_get_thread_default();
4590 if (player->context.thread_default == NULL) {
4591 player->context.thread_default = g_main_context_default();
4592 LOGD("thread-default context is the global default context");
4594 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4596 /* set sync handler to get tag synchronously */
4597 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4598 gst_object_unref(GST_OBJECT(bus));
4600 /* create gst bus_msb_cb thread */
4601 g_mutex_init(&player->bus_msg_thread_mutex);
4602 g_cond_init(&player->bus_msg_thread_cond);
4603 player->bus_msg_thread_exit = FALSE;
4604 player->bus_msg_thread =
4605 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4606 if (!player->bus_msg_thread) {
4607 LOGE("failed to create gst BUS msg thread");
4608 g_mutex_clear(&player->bus_msg_thread_mutex);
4609 g_cond_clear(&player->bus_msg_thread_cond);
4610 return MM_ERROR_PLAYER_INTERNAL;
4614 return MM_ERROR_NONE;
4618 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4620 int ret = MM_ERROR_NONE;
4621 mmplayer_gst_element_t *mainbin = NULL;
4622 MMMessageParamType msg_param = {0,};
4623 GstElement *element = NULL;
4624 MMHandleType attrs = 0;
4626 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4630 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4631 LOGE("player is not initialized");
4635 mainbin = player->pipeline->mainbin;
4636 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4638 attrs = MMPLAYER_GET_ATTRS(player);
4640 LOGE("fail to get attributes");
4644 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4646 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4647 LOGE("failed to parse profile");
4648 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4652 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4653 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4654 LOGE("dash or hls is not supportable");
4655 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4659 if (!MMPLAYER_USE_DECODEBIN(player)) {
4660 ret = _mmplayer_gst_build_pipeline_with_src(player);
4661 if (ret != MM_ERROR_NONE)
4664 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4665 LOGE("Failed to change state of uridecodebin3 element");
4671 element = _mmplayer_gst_create_source(player);
4673 LOGE("no source element was created");
4677 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4678 LOGE("failed to add source element to pipeline");
4679 gst_object_unref(GST_OBJECT(element));
4684 /* take source element */
4685 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4686 mainbin[MMPLAYER_M_SRC].gst = element;
4690 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4691 if (player->streamer == NULL) {
4692 player->streamer = _mm_player_streaming_create();
4693 _mm_player_streaming_initialize(player->streamer, TRUE);
4696 elem_idx = MMPLAYER_M_TYPEFIND;
4697 element = gst_element_factory_make("typefind", "typefinder");
4698 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4699 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4701 elem_idx = MMPLAYER_M_AUTOPLUG;
4702 element = _mmplayer_gst_make_decodebin(player);
4705 /* check autoplug element is OK */
4707 LOGE("can not create element(%d)", elem_idx);
4711 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4712 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4713 gst_object_unref(GST_OBJECT(element));
4718 mainbin[elem_idx].id = elem_idx;
4719 mainbin[elem_idx].gst = element;
4721 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4722 LOGE("Failed to link src - autoplug(or typefind)");
4726 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4727 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4728 LOGE("Failed to change state of src element");
4732 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4733 LOGE("Failed to change state of decodebin");
4738 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4739 LOGE("Failed to change state of src element");
4744 player->gapless.stream_changed = TRUE;
4745 player->gapless.running = TRUE;
4751 _mmplayer_set_reconfigure_state(player, FALSE);
4752 if (!player->msg_posted) {
4753 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4754 player->msg_posted = TRUE;